JH/03 With dkim_verify_minimal, avoid calling the DKIM ACL after the first
good verify.
+JH/04 Remove the docs and support scripts dealing with conversion of Exim
+ version 3 installations.
+
Exim version 4.98
-----------------
+++ /dev/null
-This document contains information about upgrading Exim to the last of the 3.xx
-releases. It is provided to help anybody who is upgrading to release 4.xx from
-a release that is earlier than 3.33. It goes back as far as release 2.12. If
-you are upgrading to release 4.xx from an even earlier release, it is probably
-best to start again from the default configuration.
-
-
-Upgrading from release 3.16
----------------------------
-
-1. The way LDAP returns values for multiple attributes has been changed to be
-the same as the NIS+ lookup.
-
-If you specify multiple attributes, they are returned as space-separated
-strings, quoted if necessary.
-
-e.g. ldap:///o=base?attr1,attr2?sub?(uid=fred)
-
- used to give: attr1=value one, attr2=value2
- now gives: attr1="value one" attr2=value2
-
-If you don't specify any attributes in the search, you now get them in
-the tagged format as well.
-
-e.g. ldap:///o=base??sub?(uid=fred)
-
- used to give: top, value one, value2
- now gives: objectClass=top attr1="value one" attr2=value2
-
-The reason for these changes is so that the results can be safely parsed -
-in fact, the existing ${extract{key}{val}} function does this nicely.
-This in turn allows a single LDAP query to be reused - one query can return
-the destination delivery address, the quota, and so forth.
-
-This is NOT a backwards compatible change, so there is a compile-time option
-to reverse it in the src/lookups/ldap.c module, for use in emergency. But it is
-not thought that the old behaviour was particularly useful as it stood, because
-a field that contained ',' or '=' would make the result unparseable.
-
-In the common case where you explicitly ask for a single attribute in your
-LDAP query, the behaviour is unchanged - the result is not quoted, and if there
-are multiple values they are comma-separated.
-
-2. The hosts_max_try option in the smtp transport limits the number of IP
-addresses that will actually be tried during one delivery attempt. The default
-is 5. Previously, all available addresses were tried.
-
-3. The extension of the "extract" expansion item has resulted in a change to
-the way Exim decides between the keyed form and the numeric form. If the first
-argument consists entirely of digits, the numeric form is assumed. This means
-that it is impossible to have keys that are digit strings, without manipulating
-the data first (e.g. by using ${sg} to add a letter to each key).
-
-
-Upgrading from release 3.15
----------------------------
-
-1. The handling of "freeze" and "fail" in system filter files has changed.
-Previously, any deliveries set up by a filter that ended with "freeze" or
-"fail" were discarded. This no longer happens; such deliveries are honoured.
-A consequence of this is that first_delivery becomes false after freezing in a
-system filter; previously it remained true until a real delivery attempt
-happened.
-
-
-Upgrading from release 3.13
----------------------------
-
-1. The handling of maildir_tag has been changed (see NewStuff). There are two
-small incompatibilities: (a) Exim now inserts a leading colon only if the
-string begins with an alphanumeric character. So if you were using a string
-starting with a special character, you will have to add the leading colon to
-it to remain compatible. (b) The expansion of maildir_tag now happens after the
-file has been written, and $message_size is updated to the correct file size
-before the expansion. The tag is not used on the temporary file (it was
-previously).
-
-2. The handling of Exim's configuration has changed in two ways:
-
- (a) Any line may be continued by ending it with a backslash. Trailing white
- space after the backslash, and leading white space on continuation lines is
- ignored. This means that quotes are no longer needed just to make it possible
- to continue an option setting. The difference between quoted and non-quoted
- strings is that quoted strings are processed for internal backslashed items
- such as \n. The only possible incompatibility of this change is if any
- existing configuration has a non-quoted line ended in backslash, which seems
- a very remote possibility.
-
- (b) All lists, with the exception of log_file_path, can now use a different
- character to colon as the separator. This is specified by starting the list
- with <x where x is any punctuation character. For example:
-
- local_interfaces = <; 127.0.0.1 ; ::1
-
- The new feature is provided to make life easier with IPv6 addresses. It is
- recommended that its use be confined to circumstances where it really is
- needed, and that colon be used in most cases. I don't believe this change
- is incompatible, because I don't think any list item can legitimately begin
- with a '<' character.
-
-3. Previously, Exim took no action to ensure that the timestamps in its log
-files were "wall clock time". If the TZ environment variable was set when Exim
-was called, it could cause strange times to be logged. For the majority of
-operating systems, I have been able to fix this problem by deleting the entire
-environment. However, this doesn't work in some systems, and a macro called
-HANDS_OFF_ENVIRONMENT is defined in their OS/os.h files to suppress the action.
-These OS are: AIX, DGUX, HP-UX, IRIX, and SCO, and their behaviour should be
-unchanged from previous releases. On any other OS, if you find you are getting
-weird timestamps, it may be that your OS needs HANDS_OFF_ENVIRONMENT.
-
-4. As a result of the change described in 3, there may be some cases where Exim
-runs an external program that previously got passed the environment, and now do
-not. This does *not* apply to the pipe transport, where the environment has
-always been set up specifically, as described in the manual.
-
-5. The way in which Exim scans its queue when split_spool_directory is set has
-changed, but this shouldn't make any noticeable difference. See doc/NewStuff
-for details.
-
-
-Upgrading from release 3.03
----------------------------
-
-The from_hack option in the appendfile and pipe transports has been replace by
-two string options, check_string and escape_string. If your configuration
-contains any references to from_hack they should be replaced. Exim continues to
-recognize from_hack as a transitional measure. If no_from_hack is specified in
-an appendfile transport, the two new options are forced to be unset. Otherwise
-the setting of from_hack is ignored.
-
-
-Upgrading from release 3.02
----------------------------
-
-The exim_dbmbuild utility has been changed to write a warning to stderr on
-encountering a duplicate key, and to return a value of 1. Formerly, it ignored
-all but the last of a set of duplicates; now it ignores all but the first, to
-make dbm-searched files behave the same way as lsearch-searched files. However,
-there is an option -lastdup which makes it behave as before. The -nowarn option
-suppresses the individual warnings, but the number of duplicates is always
-listed on stdout at the end.
-
-
-Updating from a release prior to 3.00
--------------------------------------
-
-Prior to release 3.00 a lot of options which contained lists of various kinds
-came in groups such as sender_accept, sender_reject, sender_reject_except. This
-style of configuration has been abolished. Instead, it is now possible to put
-negative entries in such lists, so that a single option is all that is
-required. In addition to this, net lists have been abolished, and instead,
-host lists can now contain items that specify networks as well as hosts. The
-names of some of these options have also been changed.
-
-As a result of these changes, most configuration files used for earlier
-versions of Exim need to be changed. The opportunity has therefore been taken
-to remove a number of other obsolete features and options.
-
-A Perl script is built in the file util/convert4r3 to assist in updating Exim
-configuration files. It reads a configuration file on the standard input,
-writes a modified file on the standard output, and writes comments about what
-it has done to the standard error file. It assumes that the input is a valid
-Exim configuration file. A typical call to the conversion script might be
-
- util/convert4r3 </opt/exim/configure >/opt/exim/configure.new
-
-The way the script merges an accept/reject/reject_except triple into a single
-accept option is to put the reject_except list first, followed by the reject
-list with every item negated, followed by the accept list. For example, if an
-old configuration file contains
-
- sender_host_accept_relay = *.c.d : e.f.g
- sender_host_reject_relay = *.b.c.d
- sender_host_reject_relay_except = a.b.c.d
-
-the new configuration will contain
-
- host_accept_relay = a.b.c.d : ! *.b.c.d : *.c.d : e.f.g
-
-The same ordering is used to merge a triple into a reject option, but this time
-the first and third sublists are negated. For example, if an old configuration
-file contains
-
- sender_host_accept = *.c.d : e.f.g
- sender_host_reject = *.b.c.d
- sender_host_reject_except = a.b.c.d
-
-the new configuration file will contain
-
- host_reject = ! a.b.c.d : *.b.c.d : ! *.c.d : ! e.f.g : *
-
-The output file should be checked before trying to use it. Each option change
-is preceded by an identifying comment. There are several specific things that
-you should look out for when checking:
-
-(1) If you are using macros to contain lists of items, and these have to be
- negated in the new world, convert4r3 won't get it right. For example, if
- the old configuration contains
-
- ACCEPTHOSTS = *.c.d : e.f.g
- sender_host_reject = ACCEPTHOSTS
-
- then the rewritten configuration will be
-
- ACCEPTHOSTS = *.c.d : e.f.g
- host_reject = !ACCEPTHOSTS
-
- but because this is just textual macro handling, that is equivalent to
-
- host_reject = !*.c.d : e.f.g
-
- which is not the correct translation, because the second item is not
- negated. There is unfortunately no easy way to use a macro to provide a
- list of things that are sometimes negated.
-
-(2) The conversion adds some settings of file_transport, pipe_transport, and
- reply_transport to aliasfile and forwardfile directors. This is done
- because the global implicit defaults for these options have been removed.
- The default configuration now contains explicit settings, so convert4r3
- makes these additions to be compatible with that. If your aliasfile and
- forwardfile directors do not make use of the pipe, file, or autoreply
- facilities, you can remove these new settings.
-
-(3) If you are using +allow_unknown in a host list which also has an exception
- list, you may need to move +allow_unknown in the new configuration. For
- example, if the old configuration contains
-
- sender_host_reject = +allow_unknown : *.b.c
- sender_host_reject_except = *.a.b.c
-
- then the rewritten configuration will be
-
- host_reject = ! *.a.b.c : +allow_unknown : *.b.c
-
- Because the negated item contains a wild card, the reverse lookup for the
- host name will occur before +allow_unknown is encountered, and therefore
- +allow_unknown will have no effect. It should be moved to the start of the
- list.
-
-One way of upgrading Exim from a pre-3.00 release to a post-3.00 release is as
-follows:
-
-1. Suppose your configuration file is called /opt/exim/configure, and you want
- to continue with this name after upgrading. The first thing to do is to make
- another copy of this file called, say, /opt/exim/configure.pre-3.00.
-
-2. Rebuild your existing Exim to use the copy of the configuration file instead
- of the standard file. Install this version of Exim under a special name such
- as exim-2.12, and point a symbolic link called "exim" at it. Then HUP your
- daemon. You can check on the name of the configuration file by running
-
- exim -bP configure_file
-
- Ensure that everything is running smoothly.
-
-3. Build the new release, configured to use the standard configuration file.
-
-4. Use the convert4r3 utility to upgrade your configuration file for the new
- release. After running it, check the file by hand.
-
-5. If any of the options that convert4r3 rewrote contained regular expressions
- that had backslashes in them, and were not previously in quotes, they will
- need modification if convert4r3 has put them into quotes. Either re-arrange
- the option to remove the quoting, or escape each backslash. For example, if
- you had
-
- sender_reject_recipients = ^\d{8}@
- sender_reject_except = ^\d{8}@x.y.z
-
- convert4r3 will have combined the two settings into
-
- sender_reject_recipients = "! ^\d{8}@x.y.z : \
- ^\d{8}@"
-
- This must be changed to
-
- sender_reject_recipients = ! ^\d{8}@x.y.z : ^\d{8}@
- or
- sender_reject_recipients = "! ^\\d{8}@x.y.z : ^\\d{8}@"
-
- In the second case, the quoted string could of course still be split
- over several lines.
-
-6. If your configuration refers to any external lists of networks, check them
- to ensure that all the masks are in the single-number form, because Exim no
- longer recognizes the dotted quad form of mask. For example, if an item in
- a netlist file is
-
- 131.111.8.0/255.255.255.0
-
- you must change it to
-
- 131.111.8.0/24
-
- Otherwise Exim will not recognize it as a masked IP address, and will treat
- it as a host name. The convert4r3 utility makes this conversion for networks
- that are mentioned inline in the configuration, but it does not handle
- referenced files.
-
-7. Check the newly-built Exim as much as possible without installing; you can,
- for example, use a command such as
-
- ./exim -bV
-
- in the build directory to test that it successfully reads the new
- configuration file. You can also do tests using -bt and -bh.
-
-8. Install the new release under a special name such as exim-3.00.
-
-9. You can then easily change between the new and old releases simply by moving
- the symbolic link and HUPping your daemon.
-
-
-Details of syntax changes at 3.00
-=================================
-
-1. A bare file name without a preceding search type may appear in a domain
-list; this causes each line of the file to be read and processed as if it were
-an item in the list, except that it cannot itself be a bare file name (that is,
-this facility cannot be used recursively). Wild cards and regular expressions
-may be used in the lines of the file just as in the main list.
-For example, if
-
- local_domains = /etc/local-domains
-
-then the file could contain lines like
-
- *.mydomain.com
-
-This is different to an lsearch file, which operates like any other lookup type
-and does an exact search for the key. If a # character appears anywhere in a
-line of the file, it and all following characters are ignored. Blank lines are
-also ignored.
-
-2. Any item in a domain list (including a bare file name) can be preceded by an
-exclamation mark character, to indicate negation. White space after the ! is
-ignored. If the domain matches the rest of the item, it is *not* in the set of
-domains that the option is defining. If the end of the list is reached, the
-domain is accepted if the last item was a negative one, but not if it was a
-positive one. If ! precedes a bare file name, then all items in the file are
-negated, unless they are preceded by another exclamation mark. For example:
-
- relay_domains = !a.b.c : *.b.c
-
-sets up a.b.c as an exception to the more general item *.b.c, because lists are
-processed from left to right. If the domain that is being checked matches
-neither a.b.c nor *.b.c, then it is not accepted as a relay domain, because the
-last item in the list is a positive item. However, if the option were just
-
- relay_domains = !a.b.c
-
-then all domains other than a.b.c would be relay domains, because the last item
-in the list is a negative item. In effect, a list that ends with a negative
-item has ": *" appended to it.
-
-3. Negation and bare file names are available as above in lists of local parts
-(e.g. in local_parts options) and complete addresses (address lists). For the
-special "@@" lookup form in address lists, negation also can be used in the
-list of local parts that is looked up for the domain. For example, with
-
- sender_reject_recipients = @@dbm;/etc/reject-by-domain
-
-the file could contain lines like this:
-
- baddomain.com: !postmaster : !hostmaster : *
-
-If a local part that actually begins with ! is required, it has to be specified
-using a regular expression. Because local parts may legitimately contain #
-characters, a comment in the file is recognized only if # is followed by white
-space or the end of the line.
-
-4. Host lists may now contain network items, as in the former net list options,
-which have all been abolished. The only form of network masking is the /n
-variety. Negation and bare file names can appear in host lists, and there is a
-new type of item which allows masked network numbers to be used as keys in
-lookups, thus making it possible to used DBM files for faster checking when the
-list of networks is large.
-
-The complete list of types of item which can now appear in a host list is:
-
-. An item may be a bare file name; each line of the file may take the form of
- any of the items below, but it may not itself be another bare file name. If
- the file name is preceded by ! then all items in the file are negated, unless
- they are preceded by another exclamation mark. Comments in the file are
- introduced by # and blank lines are ignored.
-
-. If the entire item is "*" it matches any host.
-
-. If the item is in the form of an IP address, it is matched against the IP
- address of the incoming call.
-
-. If the item is in the form of an IP address followed by a slash and a mask
- length (e.g. 131.111.0.0/16) then it is matched against the IP address of the
- incoming call, subject to the mask.
-
-. If the item is of the form "net<number>-<search-type>;<search-data>", for
- example:
-
- net24-dbm;/networks.db
-
- then the IP address of the incoming call is masked using <number> as the mask
- length; a textual string is then constructed from the masked value, followed
- by the mask, and this is then used as the key for the lookup. For example, if
- the incoming IP address is 192.152.34.6 then the key that is looked up for
- the above example is "192.152.34.0/24".
-
-. If the entire item is "@" the primary host name is used as the the match
- item, and the following applies:
-
-. If the item is a plain domain name, then a forward DNS lookup is done on that
- name to find its IP address(es), and the result is compared with the IP
- address of the incoming call.
-
-The remaining items require the host name to be obtained by a reverse DNS
-lookup. If the lookup fails, Exim takes a hard line by default and access is
-not permitted. If the list is an "accept" list, Exim behaves as if the current
-host is not in the set defined by the list, whereas if it is a "reject" list,
-it behaves as if it is.
-
-To change this behaviour, the special item "+allow_unknown" may appear in the
-list (at top level - it is not recognized in an indirected file); if any
-subsequent items require a host name, and the reverse DNS lookup fails, Exim
-permits the access, that is, its behaviour is the opposite to the default.
-
-. If the item starts with "*" then the remainder of the item must match the end
- of the host name. For example, *.b.c matches all hosts whose names end in
- .b.c. This special simple form is provided because this is a very common
- requirement. Other kinds of wildcarding require the use of a regular
- expression.
-
-. If the item starts with "^" then it is taken to be a regular expression which
- is matched against the host name. For example, ^(a|b)\.c\.d$ matches either
- of the two hosts a.c.d or b.c.d. If the option string in which this occurs is
- given in quotes, then the backslash characters must be doubled, because they
- are significant in quoted strings. The following two settings are exactly
- equivalent:
-
- host_accept = ^(a|b)\.c\.d$
- host_accept = "^(a|b)\\.c\\.d$"
-
-. If the item is of the form <search-type>;<filename or query>, for example
-
- dbm;/host/accept/list
-
- then the host name is looked up using the search type and file name or query
- (as appropriate). The actual data that is looked up is not used.
-
-5. Early versions of Exim required commas and semicolons to terminate option
-settings in drivers. This hasn't been the case for quite some time. The code to
-handle them has now been removed.
-
-
-Details of option changes at 3.00
-=================================
-
-Main options
-------------
-
- * address_directory_transport, address_directory2_transport,
- address_file_transport, address_pipe_transport, and address_reply_transport
- have been abolished as obsolete. The aliasfile and forwardfile directors
- have been able for some time to set the transports they want to use for
- these special kinds of delivery; there seems little need for global
- defaults. The default configuration has been altered to add settings for
- file_transport and pipe_transport to the aliasfile and forwardfile
- directors, and to add reply_transport to forwardfile.
-
- * check_dns_names, a deprecated synonym for dns_check_names, has been
- abolished.
-
- * helo_accept_junk_nets is abolished; nets can now appear in
- helo_accept_junk_hosts.
-
- * helo_verify_except_hosts and helo_verify_except_nets have been abolished,
- and helo_verify has been changed from a boolean to a host list, listing
- those hosts for which HELO verification is required.
-
- * the obsolete option helo_verify_nets (a synonym for host_lookup_nets) has
- been abolished. Note that host_lookup_nets itself has been replaced by
- host_lookup.
-
- * hold_domains_except has been abolished. Use negated items in hold_domains.
-
- * host_lookup_nets has been replaced by host_lookup, which can contain hosts
- and nets.
-
- * ignore_fromline_nets has been replaced by ignore_fromline_hosts.
-
- * If message_filter is set and the filter generates any deliveries to files,
- pipes, or any autoreplies, then the appropriate message_filter_*_transport
- options must be set to define the transports, following the abolition of
- the global defaults (see above).
-
- * queue_remote and queue_remote_except have been abolished and replaced by
- queue_remote_domains, which lists those domains that should be queued. The
- effect of queue_remote=true is now obtained by queue_remote_domains=*.
-
- * queue_smtp and queue_smtp_except have been abolished and replaced by
- queue_smtp_domains, which lists those domains that should be queued after
- routing. The effect of queue_smtp=true is now obtained by
- queue_smtp_domains=*.
-
- * rbl_except_nets has been abolished and replaced by rbl_hosts, which can
- contain hosts and nets. This defaults to "*" and defines the set of hosts
- for which RBL checking is done.
-
- * receiver_unqualified_nets is abolished; nets can now appear in
- receiver_unqualified_hosts.
-
- * receiver_verify_except_hosts and receiver_verify_except_nets have been
- abolished and replaced by receiver_verify_hosts, which defaults to "*".
- This is used, however, only when receiver_verify is set - together with the
- other conditions (receiver_verify_addresses, receiver_verify_senders).
-
- * receiver_verify_senders_except has been abolished; the functionality is now
- available by using negation in receiver_verify_senders.
-
- * rfc1413_except_hosts and rfc1413_except_nets have been abolished, and
- replaced by rfc1413_hosts, which defaults to "*".
-
- * sender_accept, sender_accept_recipients and sender_reject_except have
- been abolished; the functionality is now available via sender_reject and
- sender_reject_recipients.
-
- * sender_host_accept, sender_net_accept, sender_host_reject,
- sender_net_reject, sender_host_reject_except, sender_net_reject_except,
- sender_host_reject_recipients and sender_net_reject_recipients
- have all been abolished, and replaced by the options host_reject and
- host_reject_recipients.
-
- * sender_host_accept_relay, sender_net_accept_relay,
- sender_host_reject_relay, sender_host_reject_relay_except,
- sender_net_reject_relay, and sender_net_reject_relay_except are abolished,
- and replaced by host_accept_relay. This defaults unset, and this means that
- all relaying is now by default locked out in the Exim binary. Previously,
- if no relaying options were set, relaying was permitted.
-
- * sender_unqualified_nets has been abolished; nets can now appear in
- sender_unqualified_hosts.
-
- * sender_verify_except_hosts and sender_verify_except_nets have been
- abolished and replaced by sender_verify_hosts, which defaults to "*". This
- is used, however, only when sender_verify is set (to make it similar to
- receiver_verify, even though there aren't at present any other conditions.)
-
- * sender_verify_log_details has been abolished. This was a little-used
- debugging option.
-
- * smtp_etrn_nets has been abolished; nets can now appear in smtp_etrn_hosts.
-
- * smtp_expn_nets has been abolished; nets can now appear in smtp_expn_hosts.
-
- * smtp_log_connections, a deprecated synonym for log_smtp_connections, has
- been abolished.
-
- * smtp_reserve_nets is abolished; nets can now appear in smtp_reserve_hosts.
-
-Generic director and router options
------------------------------------
-
- * except_domains, except_local_parts, and except_senders have been abolished.
- Use negated items in domains, local_parts, and senders instead, for
- example, replace
-
- except_domains = a.b.c
-
- with
-
- domains = !a.b.c
-
- If you already have a domains setting, add any negative items to the front
- of it.
-
-The aliasfile director
-----------------------
-
- * The option "directory", an obsolete synonym for home_directory, has been
- abolished.
-
-The forwardfile director
-------------------------
-
- * The option "directory", an obsolete synonym for file_directory, has been
- abolished.
-
- * The option forbid_filter_log, an obsolete synonym for
- forbid_filter_logwrite, has been abolished.
-
-The localuser director
-----------------------
-
- * The option "directory", an obsolete synonym for match_directory, has been
- abolished.
-
-The lookuphost router
----------------------
-
- * mx_domains_except and its obsolete old name non_mx_domains have been
- abolished. Use negated items in mx_domains.
-
-The pipe transport
-------------------
-
- * The option "directory", an obsolete synonym for home_directory, has been
- abolished.
-
-The smtp transport
-------------------
-
- * mx_domains_except and its obsolete old name non_mx_domains have been
- abolished. Use negated items in mx_domains.
-
- * serialize_nets has been abolished; nets may now appear in serialize_hosts.
-
-
-Other items relevant to upgrading from Exim 2.12
-================================================
-
-1. RFC 2505 (Anti-Spam Recommendations for SMTP MTAs) recommends that the
-checking of addresses for spam blocks should be done entirely caselessly.
-Previously, although Exim retained the case of the local part, in accordance
-with the RFC 821 rule that local parts are case sensitive, some of the string
-comparisons were nevertheless done caselessly, but file lookups used the
-unmodified address.
-
-The way addresses are compared with options whose values are address lists has
-been changed. At the start of the comparison, both the local part and the
-domain are now forced to lower case, and any comparisons that are done with
-in-line strings are done caselessly. For example,
-
- sender_reject = A@b.c
-
-rejects both A@b.c and a@b.c. Any lookups that occur use lowercased strings as
-their keys. If the @@ lookup facility is used, the lookup is done on the lower
-cased domain name, but any subsequent string comparisons on local parts are
-done caselessly.
-
-To retain possibility of caseful matching, the pseudo-item "+caseful" can
-appear in an address list. It causes any subsequent items to do caseful matches
-on local parts. The domain, however, remains lower cased.
-
-2. The handling of incoming batched SMTP has been re-worked so as to behave in
-a more useful way in cases of error:
-
- (i) The option sender_verify_batch now defaults false.
- (ii) EOF is no longer interpreted as end-of-message; the "." line must be
- present.
- (iii) Exim stops immediately in cases of error, writing information to stdout
- and stderr, and setting the return code to 1 if some messages have been
- accepted, and 2 otherwise.
-
-3. The first message delivered by -R, and all messages delivered by -Rf and -qf
-are "forced" in the sense that retry information is over-ridden. Previously,
-Exim also forcibly thawed any of these messages that was frozen. This no longer
-happens. Additional options -Rff and -qff have been implemented to force
-thawing as well as delivery.
-
-4. When recipients are being rejected because the sending host is in an RBL
-list, Exim used just to show the RBL text, if any, as part of the rejection
-response. Now, if prohibition_message is set, it expands that string instead,
-with the RBL message available in $rbl_text, and $prohibition_reason set to
-"rbl_reject".
-
-5. When a trusted caller passed a message to Exim, it used to check the From:
-header against the caller's login (even though the caller was trusted) unless
-the -f option had been used to supply a different sender. This has been changed
-so that From: is never checked if the caller is trusted.
-
-Philip Hazel
-May 1999
-
+++ /dev/null
-Upgrading Exim from Release 3.33 to 4.xx
-----------------------------------------
-
-Exim 4.00 represents the largest upheaval in Exim's history. There are a lot of
-changes to the way some parts of Exim work, and a lot of incompatible changes
-to the run time configuration file.
-
-This document is in two parts. The first part contains instructions and
-suggestions for how you might go about performing the upgrade. The second part
-is a brief list of all the changes that have taken place. For full details of
-all the new features, please consult the current version of the reference
-manual.
-
-
-HOW TO UPGRADE YOUR EXIM
-------------------------
-
-When you compile Exim 4, a Perl script called convert4r4 is built in the build
-directory. It is not installed by the install script, because it is likely that
-you will run it only once.
-
-This script is provided to assist in updating Exim configuration files. It
-reads an Exim 3 configuration file on the standard input, and writes a modified
-file on the standard output. It also writes comments about what it has done to
-the standard error file. It assumes that the input is a valid Exim 3
-configuration file. A typical call to the conversion script might be
-
- ./convert4r4 </etc/exim/configure >/etc/exim/configure.new
-
-The output file MUST be checked and tested before trying to use it on a live
-system. The conversion script is just an aid which does a lot of the "grunt
-work". It does not guarantee to produce an Exim 4 configuration that behaves
-exactly the same as the Exim 3 configuration it reads.
-
-Each option change in the new file is preceded by an identifying comment. In
-fact, the conversion script tends to make quite a mess of your configuration,
-and you should expect to go through it afterwards and tidy it up by hand.
-
-Unless you are running a very straightforward configuration, the automatic
-conversion is likely to generate a non-optimal configuration. You should not
-only check it thoroughly, but also run as many tests as you can, to ensure that
-it is working as you expect. In particular, you should test address routing,
-using -bt and -bv, and the policy controls, using -bh. If possible, you should
-also do some live tests (i.e. send and receive some messages) before putting
-Exim 4 into service.
-
-If you have a very complicated configuration, it is possible that convert4r4
-will break it in some situations, which is why thorough testing is strongly
-recommended.
-
- *********************************
- ***** You Have Been Warned ******
- *********************************
-
-
-HOW TO MOVE FROM AN EXIM 3 RELEASE TO AN EXIM 4 RELEASE
--------------------------------------------------------
-
-One way of upgrading to Exim 4 from a version 3 release is as follows:
-
-1. Suppose your run time configuration file is called /usr/exim/configure, and
- you want to continue with this name after upgrading. The first thing to do
- is to make another copy of this file called, say, /usr/exim/configure.r3.
-
-2. Rebuild your existing Exim to use the copy of the run time configuration
- file instead of the standard file. Install this version of Exim and HUP your
- daemon. You can check on the name of the configuration file by running
-
- exim -bP configure_file
-
- Ensure that everything is running smoothly. You now have something you can
- fall back to. IMPORTANT: when you do this re-install, you should also
- re-install the utilities because four of them (exicyclog, eximon, exinext,
- and exiwhat) also refer to the configuration file.
-
-3. Build the new release, configured to use the standard configuration file.
-
-4. Use the convert4r4 utility to upgrade your configuration file for the new
- release. After running the conversion utility, check the file by hand, and
- tidy it up.
-
-5. Test, test, test! And test some more!
-
-6. You can run complete tests, including actual deliveries, from an uninstalled
- binary, but you have to tell it where it is, so that any re-executions can
- be done. You can do this by temporarily inserting a setting such as
-
- exim_path = /source/exim/exim-4.00/build-SunOS5-5.8-sparc/exim
-
- into the run time configuration. If you want to, you can also insert
- settings for spool_directory and log_file_path to divert those away from
- their normal places. Remember to remove these temporary settings when you
- eventually install the binary for real.
-
-7. The new installation script installs the new release as exim-4.00-1, and
- set a symbolic link called "exim" to point to it. The old version of Exim
- will be renamed to something like exim-3.33-1.
-
-8. You can now easily change between the new and old releases simply by moving
- the symbolic link and HUPping your daemon. The format of message files on
- Exim's spool has _not_ changed, so there should be no problem in changing
- between releases while there are messages on the queue.
-
-9. HOWEVER: If you do change back and forth between releases, you must also
- change the utilities exicyclog, eximon, exinext, and exiwhat if you are
- going to use them. Installing Exim 4 will have left the old versions with a
- .O suffix. It might be helpful to rename these so that you don't lose them.
-
-
-WHAT HAS NOT CHANGED IN EXIM 4.00
----------------------------------
-
-The basic overall philosophy, design, and process structure has not changed.
-The format of spool files is the same. The transports have had only minor
-modifications. The command line options remain the same, with a couple of
-additions.
-
-The general run time configuration approach has not changed, but the actual
-details of the configuration file are different.
-
-The Exim monitor has not changed, and there have been only very minor changes
-to other Exim utilities.
-
-
-WHAT HAS CHANGED IN EXIM 4.00
------------------------------
-
-The rest of this document lists the very many changes that have taken place.
-I'm going to give only brief details here, because this part of the document is
-intended as a way of alerting you to areas of difference. The reference manual
-describes how the new features work in detail.
-
-
-Named domain, host, address, and local part lists
--------------------------------------------------
-
-A new feature makes it possible to give names to lists of domains, hosts,
-addresses, and local parts. The syntax used is
-
- domainlist <name> = <a domain list>
- hostlist <name> = <a host list>
- addresslist <name> = <an address list>
- localpartlist <name> = <a list of local parts>
-
-For example:
-
- domainlist local_domains = *.my.domain
- addresslist bad_senders = cdb;/etc/badsenders
-
-These lists are referenced in options by giving the name preceded by a + sign.
-For example, in a router you might have
-
- domains = +local_domains
-
-At first sight, these lists might seem to be the same as macros, but they are
-not. Macros are just textual substitutions. If you write
-
- ALIST = host1 : host2
- auth_advertise_hosts = !ALIST
-
-it probably won't do what you want, because that is exactly the same as
-
- auth_advertise_hosts = !host1 : host2
-
-Notice that the second host name is not negated. However, if you use a host
-list, and write
-
- hostlist alist = host1 : host2
- auth_advertise_hosts = ! +alist
-
-the negation applies to the whole list, and so that is equivalent to
-
- auth_advertise_hosts = !host1 : !host2
-
-These named lists also have a performance advantage. When Exim is routing an
-address or checking an incoming message, it caches the result of tests on the
-lists. So, if you have a setting such as
-
- domains = +local_domains
-
-on several of your routers, the actual test is done only for the first one.
-However, this caching works only if there are no expansions within the list
-itself or any sublists that it references. In other words, caching happens only
-if the list is known to be the same each time it is referenced.
-
-By default, there may be up to 16 named lists of each type. This limit can be
-extended by changing a compile-time variable.
-
-The use of domain and host lists is recommended for concepts such as local
-domains, relay domains, and relay hosts. The default configuration is set up
-like this.
-
-
-Processing of domain, host, local part, and address lists
----------------------------------------------------------
-
-The handling of these lists is now more uniform. Every list is expanded as a
-single string before it is used. (In Exim 3, some options were expanded and
-some weren't, and query-style lookup items were then re-expanded.)
-
-If an expansion is forced to fail, Exim behaves as if the item has not been
-found in the list.
-
-The confusing $key variable has been abolished. When processing a domain list,
-$domain contains the relevant domain and can be used in generating database
-queries. Other appropriate variables are set when processing other kinds of
-list; $sender_host and $sender_host_address for checking incoming hosts and
-$host and $host_address for checking outgoing hosts.
-
-Note that this means that any \ and $ characters in regular expressions must be
-escaped if they appear in one of these lists. The new expansion feature to turn
-off expansion (\N ... \N) which is described below can be helpful here.
-
-IMPORTANT: The details of the processing of address lists has been revised. In
-particular, the handling of the case of an item that is a single-key lookup has
-changed. It no longer looks up the domain on its own before looking up the
-complete address. You need to supply an explicit "*@" before the lookup if you
-want just the domain to be looked up. Please check the manual for full details.
-
-If an item in a host list is the empty string, it matches only when no host is
-defined. If used when checking an incoming message, it matches only when the
-message is arriving by SMTP on the standard input from a local process (using
--bs). This provides a way of distinguishing between SMTP mail from local
-processes and from remote hosts.
-
-The +allow_unknown and +warn_unknown settings for host lists have been replaced
-by a single item, +include_unknown. By default, failure to find a host name
-when needed causes Exim to behave as if the host does not match the list, but
-if +include_unknown is set, the opposite behaviour happens. Whenever
-+include_unknown is invoked, the incident is logged.
-
-
-Merge of Directors and Routers
-------------------------------
-
-There are no longer any directors in Exim 4. There are just routers. All
-addresses are passed to a single list of routers which typically makes use of
-the "domains" option to choose which way to handle specific groups of domains.
-
-A consequence of this is that the code no longer contains any concept of "local
-domains". However, a typical configuration will probably define a named domain
-list (see above) called local_domains, and use it to control routing something
-like this:
-
- route_remote:
- driver = dnslookup
- domains = ! +local_domains
- transport = remote_smtp
- no_more
-
- system_aliases:
- ....
-
-The first router does DNS routing for all domains that are not in the named
-list of local domains, and no_more ensures that it is the last router for those
-domains. All other domains fall through to the system_aliases and subsequent
-routers. For a complete configuration example, look at the default
-configuration file in src/configure.default.
-
-
-Router Actions
---------------
-
-The concept of how the routers work is as follows:
-
-A number of pre-conditions are tested (details below). If any of them fails,
-control is passed to the next router. We say "the router is skipped". Otherwise
-the router is run, and can yield one of several different results:
-
-. accept: The router accepts the address, and either queues it for a transport,
-or generates one or more "child" addresses. Processing the original address
-ceases, unless "unseen" is set on the router, in which case the address is
-passed to the next router. Processing of any child addresses starts with the
-first router by default, or at the router defined by redirect_router if it is
-set. This may be any router in the list.
-
-. decline: The router declines to accept the address because it does not
-recognize it at all. The address is passed to the next router, unless no_more
-is set, in which case the address fails.
-
-. pass: The router recognizes the address, but cannot handle it itself. It
-requests that the address be passed to another router. This overrides no_more.
-By default the address is passed to the next router, but this can be changed by
-setting pass_router. However, in this case (unlike redirect_router) the named
-router must be below the current router (to avoid loops).
-
-. fail: The router determines that the address should fail, and queues it for
-the generation of a bounce message. There is no further processing of the
-original address, unless "unseen" is set.
-
-. defer: The router cannot handle the address at the present time. (For
-example, a database may be offline.) No further processing of the address
-happens in this delivery attempt. It is tried again next time.
-
-. error: There is some error in the router (for example, a syntax error in
-its configuration). The action is as for defer.
-
-
-Router pre-conditions
----------------------
-
-In Exim 3 there are some strange interactions between the generic options that
-test things before running a director or router and the no_more test that
-happens afterwards.
-
-In Exim 4 it is all more straightforward. If any of the pre-condition tests
-fail, the router is skipped and control passes to the next router. The no_more
-option has an effect only if the router is actually run - that is, if all the
-pre-condition tests succeed. The order in which these tests are run is:
-
- verify status, expn status, domains, local_parts, check_local_user
-
-If all those match, the debug_print string is output when debugging. Exim then
-goes on to test
-
- senders, require_files, condition
-
-Note that require_files comes near the end of the list, so you cannot use it to
-check for the existence of a file in which to lookup up a domain, local part,
-or sender. However, as these options are all expanded, you can use the "exists"
-expansion condition to make such tests. The require_files option is intended
-for checking files that the router may be going to use internally, or which are
-needed by a specific transport (e.g. .procmailrc).
-
-In Exim 4, local part prefixes and suffixes are recognized and removed before
-any of the other pre-condition tests are done (in Exim 3 they were removed
-afterwards). Note that this means that the local_parts option now tests the
-local part without its prefix or suffix.
-
-If you want to use local parts that include any affixes in a pre-condition
-test, you can do so by using a "condition" option that uses the variables
-$local_part, $local_part_prefix, and $local_part_suffix as necessary.
-
-
-A New Set of Routers
---------------------
-
-The two sets of routers and directors of Exim 3 have been replaced by a single
-set of routers for Exim 4. These are as follows:
-
-. accept Always accepts an address. It has no private options.
-
-. dnslookup Routes by DNS lookup (descended from lookuphost).
-
-. ipliteral Routes IP literal addresses (unchanged).
-
-. iplookup Special-purpose lookup router (unchanged).
-
-. manualroute Routes domains from explicit data (descended from domainlist).
-
-. queryprogram Routes addresses by running a program (detail changed).
-
-. redirect Redirects addresses; handles all the functions previously
- supported by aliasfile, forwardfile, and smartuser without
- a transport.
-
-
-Saving duplication of effort while routing
-------------------------------------------
-
-Early versions of Exim used to copy the routing of one address for all other
-addresses in the same domain, thereby possibly saving some repeated DNS
-lookups. This feature was removed for release 2.12, after the possibility of
-varying the router actions according to the local part (the local_parts option)
-was added. (In fact, the use of $local_part could have broken it earlier.)
-
-For Exim 4, I have added an option called same_domain_copy_routing to the
-dnslookup and manualroute routers. When one of these routers routes an address
-to a remote transport and this option is set, any other addresses in the
-message that have the same domain are automatically given the same routing, but
-only if the router does not set headers_add or headers_remove, and does not
-`widen' the domain during the routing.
-
-
-Generic Router Options
-----------------------
-
-. The global locally_caseless option is replaced by a generic router option
- called caseful_local_part. By default, routers handle local parts caselessly.
-
-. check_local_user is now a generic option that is needed to check for a local
- account. Typically used on redirect (for user's forward files) and on accept
- (for local deliveries).
-
-. The setting self=local has been removed (since there's no concept of local
- domains in the code). The same kind of effect can be achieved by using
- self=reroute or self=pass.
-
-. expn is now a generic router option.
-
-. local_part_prefix and local_part_suffix are now generic router options,
- replacing prefix and suffix on directors.
-
-. Exim 3 has two logging styles for delivery, depending on whether the domain
- is a local domain or not. For local domains, the address is given just as the
- local part - this makes these deliveries easier to spot in the log. In Exim 4
- there's no concept of local domains, so this functionality cannot be
- automatic. Instead, there's a generic router option called log_as_local which
- requests "local-style" logging. This option defaults on for the "accept"
- router, and off for all the others.
-
-. There's an option called retry_use_local_part which is the default for any
- router that has check_local_user set, and it applies to routing delays. (The
- same option for transports applies to transport delays.)
-
-. transport_home_directory and transport_current_directory are new generic
- options on all routers. They set up default values for home_directory and
- current_directory on the transport to which they route an address. Any
- settings in the transport override.
-
-. If transport_home_directory is not set, but check_local_user is set, the
- user's home directory is used as a default value.
-
-. The special fudge that exists in Exim 3 for handling home_directory settings
- in forwardfile directors is not needed in Exim 4. It has therefore been
- removed.
-
-. The new_director option in Exim 3 allows the direction of redirected
- addresses to start at a given director, instead of the first one. In Exim 4,
- this option is now called redirect_router. The option is used when a redirect
- router succeeds, and when a queryprogram router returns a "redirect"
- response.
-
-. There is a new option called pass_router, which specifies the router to go to
- when a router "passes" on an address. The named router must follow the
- current router (to avoid routing loops). Note: if a router declines, control
- always passes to the next router, unless no_more is set.
-
-. There is a new router option called address_data. This is set to a string
- which is expanded just before the router is run, that is, after all the
- pre-tests have succeeded. If the expansion is forced to fail, the router
- declines. Other expansion failures cause delivery of the address to be
- deferred.
-
- When the expansion succeeds, the value is retained with the address, and can
- be accessed using the variable $address_data. Even if the router declines or
- passes, the value remains with the address, though it can be changed by
- another address_data setting on a subsequent router. If a router generates
- child addresses, the value of $address_data propagates to them.
-
- The idea of address_data is that you can use it to look up a lot of data for
- the address once, then then pick out parts of the data later. For example,
- you could use an LDAP lookup to return a string of the form
-
- uid=1234 gid=5678 mailbox=/mail/xyz forward=/home/xyz/.forward
-
- In the transport you could then pick out the mailbox by a setting such as
-
- file = ${extract{mailbox}{$address_data}}
-
- This makes the configuration file less messy, and also reduces the number of
- lookups. (Exim does cache the most recent lookup, but there may be several
- addresses with different lookups.)
-
-. When a transport is run for several addresses simultaneously, the values of
- $address_data, $local_part_data, and $domain_data are taken from the first
- address that the transport handles. However, the order in which multiple
- addresses are processed is not defined. You therefore need to be careful if
- you want to use these variables with multiple addresses. The smtp transport
- is the only one which by default handles multiple addresses.
-
-. When an address is routed by a router with the "unseen" option set, a "clone"
- address is created, and it starts being routed at the next router. (This is
- what people expect. In Exim 3 it starts at the top - in simple cases that has
- the same effect because of the anti-looping rule, but if aliases are involved
- it sometimes doesn't do what you want.)
-
-. The way that require_files works has been changed. Each item in the list is
- now separately expanded as the test proceeds. The use of leading ! and +
- characters is unchanged. However, user and group checking is done differently.
- Previously, seteuid() was used, but seteuid() is no longer used (see
- "Security" below) for checking the files required by this option. Instead,
- Exim now scans along the components of the file path and checks the access
- for the given uid and gid. It expects "x" access on directories and "r" on
- the final file. This means that file access control lists (on those
- operating systems that have them) are ignored.
-
-
-Other Consequences of the Director/Router Merge
------------------------------------------------
-
-. The -odqr option is abolished, as there is no inbuilt concept of remote
- domains.
-
-. The -odqs option is equivalent to queue_smtp_domains = *.
-
-. queue_remote_domains is renamed queue_domains, and applies to any domain.
-
-. The -ql option now suppresses remote delivery; routing always happens.
-
-. The "remote" facility of queue_only_file has been removed.
-
-. The match_directory option for forwardfile and localuser has been entirely
- abolished. Its function can be achieved using the "condition" option in
- conjunction with check_local_user.
-
-. When an address is being verified, if it is redirected to a single new
- address, verification continues with that address. If it is redirected to
- more than one address, verification ceases with a success result. (In Exim 3,
- this applied only to aliasing, not to forwarding.)
-
-
-The dnslookup router
---------------------
-
-This router replaces the lookuphost router of Exim 3. It is much the same,
-except that the "gethostbyname" option has been removed. It now does only DNS
-routing - hence the change of name. Routing using gethostbyname() can be done
-by the manualroute router.
-
-
-The manualroute router
-----------------------
-
-This is the new name for the domainlist router, supposedly to make its function
-clearer and to avoid confusion with the "domainlist" that is used to set up
-named domain lists. Several things have been removed and reorganized.
-
-. The old search mechanism (route_file, route_query, route_queries,
- search_type) have been removed. Instead there is a new option called
- route_data, which is an expanded string. It should expand to a single routing
- entry. If the expansion ends up empty (or is forced to fail), the router
- declines. The route_list option still exists, for convenient listing of a few
- inline routes.
-
-. There is no longer any MX processing function in this router. The keywords
- bydns_mx and bydns_a have been removed, leaving just
-
- bydns => find IP addresses from address records in the DNS
- byname => find IP addresses by calling gethostbyname()
-
- The default lookup type is "byname", and this can be omitted from a route
- data line. If an IP address is given, both "byname" and "bydns" are ignored
- (so typically you omit this field).
-
-. The qualify_single and search_parents options have also been removed.
-
-. A transport is always required to be set, unless verify_only is set.
-
-. The host_find_failed option can be set to "decline", to cause the router to
- decline if it can't find an IP address for a listed host.
-
-. If manualroute routes to a local transport, there is no need to specify
- byname or bydns in the routing data. Any supplied host list is passed as a
- string in $host, but $host_address is unset.
-
-
-The queryprogram router
------------------------
-
-This router has been re-designed:
-
-. You must now specify a user and group for the program to be run using
- command_user and (if necessary) command_group. It no longer defaults to
- "nobody". These options are expanded.
-
-. The command is now split up and each argument expanded separately, as happens
- for the pipe transport. The command name is also expanded.
-
-. The return value "forcefail" has been renamed "fail", and it causes delivery
- to fail. (The original usage of "fail" meaning "decline" has finally been
- removed.)
-
-. The $route_option variable, which queryprogram used to be able to set has
- been abolished. A facility to set the new $address_data variable replaces it.
-
-. The string returned from queryprogram must now be one of:
-
- DECLINE
- FAIL text
- DEFER text
- PASS
- FREEZE text
- REDIRECT text
- ACCEPT TRANSPORT=transport HOSTS=host list LOOKUP=byname|bydns DATA=text
-
-The text returned for "redirect" is a list of new addresses. The text for FAIL
-is returned in the SMTP dialogue when the router is run as part of address
-verification. It is also logged. The text for DEFER and FREEZE is just logged.
-
-The data items in the "accept" return can be given in any order, and all are
-optional. If no transport is included in the "accept" return, the router's
-default transport is used. The host list and lookup type are needed only if the
-transport is an smtp transport that does not itself have a host list. The
-default lookup type is "byname". If the "data" field is set, its value is
-placed in the $address_data variable.
-
-
-The redirect router
--------------------
-
-This router replaces forwardfile, appendfile, and the use of smartuser without
-a transport. It has two mutually exclusive options for specifying the data that
-it uses. If "file" is set, the data is taken from a file. Otherwise "data" must
-be set, and the data is the expanded value of that option.
-
-The data may be an alias list, possibly including special entries such as
-:fail:, or it may be a list of filtering instructions.
-
-If "file" is set, but the file does not exist or is empty, or its contents have
-no effect (entirely comments, or a filter that does nothing), the router
-declines. This also happens if the expansion of "file" is forced to fail. Any
-other expansion failure causes the router to defer.
-
-Ownership of the file is checked if check_local_user is set or if owners is
-set, unless check_owner is explicitly set false.
-
-Likewise, the group is checked if owngroups is set, or if check_local_user is
-set and a modemask not containing 020 is set, unless check_group is explicitly
-set false.
-
-If "data" is set, a forced expansion causes the router to decline. This also
-happens if "data" is an empty string or a string that causes nothing to be
-generated and no action to be taken.
-
-Because "data" is now used for traditional /etc/aliases lookups, an empty alias
-no longer gives an error. It behaves in the same way as :unknown: (which is
-still recognized, but ignored).
-
-. If no_repeat_use is set, the router is skipped if _any_ ancestor of the
- current address was routed by this router. This pre-test happens before any
- of the others. (Contrast the default loop avoidance logic, which skips a
- router if an ancestor with the same local part was routed by the router.)
-
-. If include_directory is set, :include: files are constrained to this
- directory.
-
-. When an address is redirected to a file or a pipe, $address_file or
- $address_pipe (as appropriate) is set when expanding the value of
- file_transport or directory_transport.
-
-. There are new options forbid_filter_readfile and forbid_filter_run to lock
- out the use of the new ${readfile and ${run expansion items in filters.
-
-. If one_time is set, forbid_pipe, forbid_file, and forbid_filter_reply are
- forced to be true, and headers_add and headers_remove are forbidden.
-
-
-Generic transport options
--------------------------
-
-. All remote deliveries are now done in subprocesses running with specified
- UIDs and GIDs. (Formerly, only remote parallel deliveries were done in
- subprocesses.) As a result, user and group are now generic options that can
- be used on all transports. The default for both local and remote transports
- is to run as the Exim user and group. For remote transports, this should not
- normally be changed, but if it is, the user or group should be able to access
- the hints databases, though failure to open a hints database is always
- ignored.
-
- If it turns out that a transport user is in the never_users list, Exim now
- defers delivery and writes to the panic log. (Previously it just ran the
- delivery as "nobody".) Because subprocesses (usually running as "exim")
- are now always used for remote deliveries, you should *not* include "exim" in
- the never_users list.
-
-. initgroups is now also a generic transport option.
-
-. home_directory and current_directory are generic options on all transports,
- though some transports (e.g. smtp) make no use of them. If they are unset,
- values supplied by the router are used.
-
-. The message_size_limit option is now expanded, which makes it possible to
- have different limits for different hosts, for example.
-
-
-Multiple (batch) deliveries in the appendfile, lmtp, and pipe transports
-------------------------------------------------------------------------
-
-The options controlling batch deliveries, including BSMTP, were a mess, and
-have been reworked.
-
-. The batch option has been removed from all three transports, and the bsmtp
- and bsmtp_helo options have been removed from appendfile and pipe.
-
-. The batch_max option defaults to 1 in all three transports.
-
-. A new option called use_bsmtp has been added to appendfile and pipe. When
- set, the message is delivered in BSMTP format. If you want to have a HELO
- line at the start of the message, you can configure this by making use of the
- message_prefix option. You must include the terminating newline.
-
-. A new option called batch_id has been added to all three transports.
-
-Batching is now achieved by setting batch_max to a value greater than 1. This
-is recommended for lmtp. When multiple addresses are routed to the same
-transport that has a batch_max value greater than one, the addresses are
-delivered in a batch, subject to certain conditions:
-
-. If any of the transport's options contain a reference to "$local_part", no
- batching is possible.
-
-. If any of the transport's options contain a reference to "$domain", only
- addresses with the same domain are batched.
-
-. If batch_id is set, it is expanded for each address, and only those addresses
- with the same expanded value are batched.
-
-. Batched addresses must also have the same errors address (where to send
- delivery errors), the same header additions and removals, the same user and
- group for the transport, and if a host list is present, the first host must
- be the same.
-
-
-The appendfile transport
-------------------------
-
-. The prefix and suffix options have been renamed message_prefix and
- message_suffix to avoid confusion with address affixes. The default values,
- which are suitable for mbox deliveries, now apply only if "file" is set and
- use_bsmtp is not set. Otherwise, the default values for these options are
- unset. They can, of course, always be overridden.
-
-. If "directory" is set (which means that "file" is not set), the check_string
- and escape_string options now default unset.
-
-. The require_lockfile options has been abolished. If use_lockfile is set, a
- lock file is always required.
-
-. The quota_filecount option is now expanded.
-
-. The create_file option now also applies when delivering into an individual
- file in a given directory, as well as when appending to a single file. In the
- case of maildir delivery, the restriction applies to the top directory of the
- maildir folder.
-
-. There's a new option called directory_file which is expanded to form the
- final leaf name of files when "directory" is set, but neither maildir nor
- mailstore is set. The default is "q${base62:$tod_epoch}-$inode", which
- reproduces the old fixed value. The variable $inode is available only when
- expanding this new option.
-
-
-The pipe transport
-------------------
-
-. The prefix and suffix options have been renamed message_prefix and
- message_suffix to avoid confusion with address affixes. The default values
- that are suitable for vacation deliveries now apply only if use_bsmtp is not
- set. Otherwise the default values for these options are unset. They can, of
- course, always be overridden.
-
-
-The smtp transport
-------------------
-
-. The badly-named batch_max option is now called connection_max_messages.
-
-. If hosts_randomize is set, it now affects host lists that come from a router
- as well as the contents of the "hosts" option, but only if the hosts were not
- obtained from MX records. Typically, such lists come from the manualroute
- router. This change means that the router can provide the same host list for
- multiple addresses - causing them all to be sent to the transport at once.
- Randomizing is then done each time the transport is called. (If you set
- hosts_randomize on the router, the randomizing happens for each address.)
-
-. The way that smtp operates when there are multiple addresses to be sent to
- the same host is now different. Previously, the transport was called many
- times, with a maximum of max_rcpt addresses per call. Each call made a new
- connection to the host. When remote_max_parallel = 1, all the addresses are
- now passed to the transport at once. It makes a single TCP/IP call, but may
- send multiple copies of the message, each with no more than max_rcpt
- recipients.
-
- When remote_max_parallel is greater than 1, a heuristic is used. The number
- of addresses passed to a single call of the transport is limited to
-
- (the total number of recipients) / (the value of remote_max_parallel)
-
- so, for example, if there are 100 recipients and remote_max_parallel is 2, no
- more than 50 are passed in one call, even if max_rcpt is 100. (The idea is
- that the other 50 will be passed to another call running in parallel.)
-
- There is an option of the smtp transport called connection_max_messages
- which limits the number of messages, or copies of a message, that Exim sends
- down a single TCP/IP connection. This applies both to this mechanism for
- multiple copies of a single message, and the re-use of a TCP/IP connection
- for sending other messages destined for the same host, after a delivery
- delay. The default value is 500.
-
-. The "interface" option is now expanded. If the result is a forced failure or
- an empty string, it is ignored. Otherwise, the result must be a list of IP
- addresses. The first one of the correct type (IPv4 or IPv6) for the outgoing
- connection is used. If there isn't one of the correct type, the option is
- ignored.
-
-. At the start of running the transport, the value of $host is taken from the
- first host in a multi-host list. However, just before the transport connects
- to a host, the value is changed to refer to that particular host. (This
- applies to $host_address as well.) This means that options such as helo_data
- and the tls_options can be made host-specific.
-
-. The tls_verify_ciphers option has been renamed tls_require_ciphers, in order
- to leave the word "verify" as something that refers to the verification of
- certificates.
-
-. The resolution of hosts and fallback_hosts used to look up MX records. This
- was some kind of ancient silliness that I recently noticed. These are
- definitely hosts, not mail domains. Exim 4 just looks up address records.
- As a consequence of this, the mx_domains option of the smtp transport is
- removed.
-
-. The authenticate_hosts option has been renamed as hosts_try_auth. A new
- option called hosts_require_auth has been added; if authentication fails for
- one of these hosts, Exim does _not_ try to send unauthenticated. It defers
- instead. The deferral error is detectable in the retry rules, so this can be
- turned into a hard failure if required.
-
-
-The System Filter
------------------
-
-. The system filter options that were called message_filter_xxx have all been
- renamed as system_filter_xxx.
-
-. The value of system_filter is expanded.
-
-. message_filter_directory_transport and message_filter_file_transport are now
- both expanded before use. If the filter set up any file or pipe deliveries,
- $address_file and $address_pipe are set as appropriate while doing the
- expansions.
-
-. message_filter_directory2_transport has been removed. The effect of using
- different directory-style transports can be achieved by specifying a suitable
- expansion string to system_filter_directory_transport.
-
-. When a system filter added recipients to a message, Exim 3 added an
- X-Envelope-To: header, listing the real recipients (up to 100). This has been
- abolished because you can do this kind of thing using "headers_add" nowadays.
-
-. The "fail" command has been extended to allow for two different messages, one
- for Exim's log and the other to be returned to the sender. The syntax is
-
- fail "<<log message>>user message"
-
- That is, if the first two characters of the message are "<<" the following
- text, up to ">>", is written to the log, and the remainder is returned to the
- user. If there is no log message, the user message is logged. The motivation
- for this feature was to reduce the amount of text logged, while being able to
- send quite long (maybe even multi-line) messages back to the sender.
-
-
-Changes to Lookups
-------------------
-
-. Oracle support is available. It works like the mysql and pgsql support,
- except that there is no "database name" involved, and the "host name" field
- is used for what is called "service name" in Oracle. This often looks like a
- host name. Also, semicolons are not used at the end of an SQL query for
- Oracle.
-
-. There's a new single-key lookup type called dsearch. It searches a directory
- for a file whose name matches the key. The result of a successful search is
- the key. One possible use of this could be for recognizing virtual domains.
- If each domain is represented by a file whose name is the domain name, you
- needn't make a separate list of the domains. You could test for them in an
- ACL (see below), for example, by a line like this
-
- accept domains = dsearch;/etc/virtual/domains
-
-. The format of LDAP output has been changed for cases where multiple
- attributes are requested. The data for each attribute is now always quoted.
- Within the quotes, the quote character, backslash, and newline are escaped
- with backslashes and commas are used to separate multiple values for the
- attribute. Thus, the string in quotes takes the same form as the output when
- a single attribute is requested. If multiple entries are found, their data is
- still separated by a newline.
-
-. There's a new expansion condition called ldapauth which exists so that the
- LDAP authentication mechanism can be used for user authentication. It is
- described under "string expansion" below.
-
-. Exim now supports ldaps:// URLs as well as ldap:// URLs. The former do LDAP
- over TLS (i.e. encrypted) connections.
-
-. There is now support for the "whoson" mechanism for doing "POP-before-SMTP"
- authentication. This is provided by new query-style lookup type called
- "whoson", with queries that consist of IP addresses. For example, in an ACL
- you can write
-
- require condition = ${lookup whoson {$sender_host_address}{yes}{no}}
-
-
-Special items in domain and host lists
---------------------------------------
-
-. In a domain list, the special item @ matches the primary host name, and the
- special item @[] matches any local interface address enclosed in square
- brackets (as in domain literal email addresses). The special item @mx_any
- matches any domain that has an MX record pointing to the local host. The
- special items @mx_primary and @mx_secondary are similar, except that the
- first matches only when the primary MX is to the local host, and the second
- only when the primary MX is not the local host, but a secondary MX is.
-
-. In a host list, the special item @ matches the primary host name, and the
- special item @[] matches any local interface address (not in brackets).
-
-
-Access Control Lists (ACLs)
----------------------------
-
-All the policy control options for incoming messages have been replaced by
-Access Control Lists (ACLs). These give more flexibility to the sysadmin, and
-allow the order of testing to be specified. For example, using an ACL, it is
-possible to specify "accept if authenticated, even if from an RBL host, but
-otherwise deny if from an RBL host", which is not possible in Exim 3.
-
-ACLs are defined in a new part of the configuration file, and given names.
-Which ones to run are controlled by a new set of options that are placed in the
-main part of the configuration.
-
- acl_smtp_auth specifies the ACL to run when AUTH is received
- acl_smtp_data specifies the ACL to run after a message has been received
- acl_smtp_etrn specifies the ACL to run when ETRN is received
- acl_smtp_expn specifies the ACL to run when EXPN is received
- acl_smtp_rcpt specifies the ACL to run when RCPT is received
- acl_smtp_vrfy specifies the ACL to run when VRFY is received
-
-The default actions vary. If acl_smtp_auth is not defined, AUTH is always
-accepted (and an attempt is made to authenticate the session). If acl_smtp_data
-is not defined, no checks are done after a message has been received, and it is
-always accepted at that point.
-
-However, if any of the others are not defined, the relevant SMTP command is
-rejected. In particular, this means that acl_smtp_rcpt must be defined in order
-to receive any messages over an SMTP connection. The default configuration file
-contains a suitable default for this.
-
-ACLs can be provided in line, or in files, or looked up from databases. One ACL
-can call another in a subroutine-like manner. String expansion is used, and
-which ACL to run can be varied according to sender host or any other criterion
-that a string expansion can test.
-
-This is not the place to give a full specification of ACLs, but here is a
-typical example for checking RCPT commands, taken from the default
-configuration. The tests are performed in order.
-
-acl_check_rcpt:
- # Accept if source is local SMTP (i.e. not over TCP/IP - undefined host)
- accept hosts = :
-
- # Deny if the local part contains @ or % or /
- deny local_parts = ^.*[@%/]
-
- # Accept mail to postmaster in any local domain, regardless of the source,
- # and without verifying the sender.
- accept domains = +local_domains
- local_parts = postmaster
-
- # Deny unless the sender address can be verified.
- require verify = sender
-
- # Accept if the address is in a local domain, but only if the recipient can
- # be verified. Otherwise deny. The "endpass" line is the border between
- # passing on to the next ACL statement (if tests above it fail) or denying
- # access (if tests below it fail).
- accept domains = +local_domains
- endpass
- message = unknown user
- verify = recipient
-
- # We get here only for non-local domains. Accept if the message arrived over
- # an authenticated connection, from any host. These messages are usually from
- # MUAs, so recipient verification is omitted.
- accept authenticated = *
-
- # Reaching the end of the ACL causes a "deny", but we might as well give
- # an explicit message.
- deny message = relay not permitted
-
-The following options have been abolished as a consequence of the introduction
-of ACLs:
-
-auth_hosts, auth_over_tls_hosts, headers_checks_fail, headers_check_syntax,
-headers_sender_verify, headers_sender_verify_errmsg, host_accept_relay,
-host_auth_accept_relay, host_reject_recipients, prohibition_message,
-rbl_domains, rbl_hosts, rbl_log_headers, rbl_log_rcpt_count,
-rbl_reject_recipients, rbl_warn_header, receiver_try_verify, receiver_verify,
-receiver_verify_addresses, receiver_verify_hosts, receiver_verify_senders,
-recipients_reject_except, recipients_reject_except_senders, relay_domains,
-relay_domains_include_local_mx, relay_match_host_or_sender,
-sender_address_relay, sender_address_relay_hosts, sender_reject,
-sender_reject_recipients, sender_try_verify, sender_verify,
-sender_verify_batch, sender_verify_hosts, sender_verify_fixup,
-sender_verify_hosts_callback, sender_verify_callback_domains,
-sender_verify_callback_timeout, sender_verify_max_retry_rate,
-sender_verify_reject, smtp_etrn_hosts, smtp_expn_hosts. smtp_verify, tls_hosts.
-
-The variable $prohibition_reason has been abolished.
-
-The host_reject option has been retained, but with its name changed to
-host_reject_connection, to emphasize that it causes a rejection at connection
-time. I've left it available just in case it is needed - but its use is not
-recommended in normal circumstances.
-
-
-Other Incoming SMTP Session Controls
-------------------------------------
-
-. The option smtp_accept_max_per_connection (default 1000) limits the number of
- messages accepted over a single SMTP connection. This is a safety catch in
- case some sender goes mad (incidents of this kind have been seen). After the
- limit is reached, a 421 response is given to MAIL commands.
-
-. Some sites find it helpful to be able to limit the rate at which certain
- hosts can send them messages, and the rate at which an individual message can
- specify recipients. There are now options for controlling these two different
- rates.
-
- Rate limiting applies only to those hosts that match smtp_ratelimit_hosts,
- whose value is a host list. When a host matches, one or both of the options
- smtp_ratelimit_mail and smtp_ratelimit_rcpt may be set. They apply to the
- rate of acceptance of MAIL and RCPT commands in a single SMTP session,
- respectively.
-
- The value of each option is a set of four comma-separated values:
-
- 1. A threshold, before which there is no rate limiting.
- 2. An initial time delay. Unlike other times in Exim, fractions are allowed
- here.
- 3. A factor by which to increase the delay each time.
- 4. A maximum value for the delay.
-
- For example, these settings have been used successfully at the site which
- first suggested this feature, for controlling mail from their customers:
-
- smtp_ratelimit_mail = 2, 0.5s, 1.05, 4m
- smtp_ratelimit_rcpt = 4, 0.25s, 1.015, 4m
-
-. The default value for smtp_connect_backlog has been increased to 20.
-
-. The SMTP protocol specification requires the client to wait for a response
- from the server at certain points in the dialogue. (Without PIPELINING these
- are after every command; with PIPELINING they are fewer, but still exist.)
- Some spamming sites send out a complete set of SMTP commands without waiting
- for any response. Exim 4 protects against this by rejecting messages if the
- client has sent further input when it should not have. The error response
- "554 SMTP synchronization error" is sent, and the connection is dropped.
-
- This check is controlled by smtp_enforce_sync, which is true by default.
-
-. helo_strict_syntax has been abolished. The default is now to enforce strict
- domain syntax for HELO/EHLO arguments. You can use helo_accept_junk_hosts if
- you want to avoid this.
-
-. There's a new option called helo_lookup_domains. If the domain given in a
- HELO or EHLO command matches this list, a reverse lookup is done in order to
- establish the host's true name. The default setting is
-
- helo_lookup_domains = @ : @[]
-
- That is, a lookup is forced if the client host gives the server's name or
- [one of its IP addresses] in HELO or EHLO. (In Exim 3 this happened
- automatically and was not configurable.)
-
-. The value of the global message_size_limit option is now expanded. For
- locally submitted messages this happens at the start of message reception.
- For messages from remote hosts, the expansion is done just after the host
- connects, so that the value can depend on the host.
-
-
-Handling of Resent- Fields
---------------------------
-
-RFC 2822 makes it clear that Resent- fields are purely informational. Exim used
-to make use of Resent-Reply-To: which does not actually exist, and it also used
-to use the last set of resent- fields for all the address fields it recognized.
-
-In Exim 4, resent- headers are dealt with as follows:
-
-. A Resent-From: header that just contains the login id as the address is
- automatically rewritten in the same way as From: is (using qualify domain,
- and user name from the passwd data).
-
-. If there's a rewrite rule for a header, it is also applied to resent- headers
- of the same type. For example, a rule that rewrites From: headers also
- rewrites Resent-From: headers.
-
-. For local messages, if Sender: is being removed on input, Resent-Sender: is
- also removed.
-
-. If there are any resent- headers but no Resent-Date: or Resent-From: they are
- added.
-
-. The logic for adding Sender: is now duplicated for Resent-Sender.
-
-. If there's no Resent-Message-Id: one is created, and it is the
- Resent-Message-Id: which is included in the log line.
-
-
-Authentication
---------------
-
-. The auth_hosts option has been abolished; this functionality is now
- controlled by ACLs.
-
-. The auth_always_advertise option has been abolished because it depended on
- auth_hosts and host_auth_accept_relay, both of which are no more. In its
- place there is a new option called auth_advertise_hosts, whose default value
- is *, meaning "advertise AUTH to all".
-
-. The value of server_setid is now used when logging failed authentication
- attempts.
-
-. The -oMaa option allows trusted users to set the value of
- $sender_host_authenticated (the authenticator name). This is normally used in
- conjunction with -oMa.
-
-
-Encryption
-----------
-
-. Because tls_hosts is no more, tls_advertise_hosts is now the only means of
- controlling the advertisement of STARTTLS (previously, tls_hosts overrode).
-
-. The global option tls_verify_ciphers has been abolished. There are now
- facilities for checking which cipher is in use in ACLs.
-
-. There's a new option called tls_try_verify_hosts. Like tls_verify_hosts, this
- causes the server to request a certificate from a client, and it verifies the
- certificate that it receives. However, unlike tls_verify_hosts, Exim
- continues with the SMTP connection (encrypted) if a client certificate is not
- received, or if the certificate does not verify. This state can be detected
- in an ACL, which makes it possible to implement policies such as "accept for
- relay only if a verified certificate has been received but accept for local
- delivery if encrypted, even without a verified certificate".
-
- A match in tls_verify_hosts overrides tls_try_verify_hosts.
-
-
-The Daemon
-----------
-
-. local_interfaces can now specify a port number with each address, thus
- allowing a single Exim daemon to listen on multiple ports. The format of each
- address is either [aaaa]:ppp or aaaa.ppp where aaaa is an IP address and ppp
- is a port number. For example:
-
- local_interfaces = 192.168.3.4.25 : 192.168.3.4.26
-
- If an address is listed without a port, the setting of daemon_smtp_port, or
- the value of the -oX option, is the default.
-
-. The -oX option can now override local_interfaces. That is, it can supply IP
- addresses as well as just a port. It is interpreted in this way if its value
- contains any of the characters . : or []. For example:
-
- exim -bd -oX 10.9.8.7:10.11.12.13.2525
-
- The format of the string is identical to the format recognized by the
- local_interfaces option.
-
-. The way the daemon wrote PID files was overly complicated and messy. It no
- longer tries to be clever. A PID file is written if, and only if, -bd is used
- and -oX is _not_ used. In other words, only if the daemon is started with its
- standard options. There is only one PID file. If pid_file_path is unset, it
- is exim-daemon.pid in Exim's spool directory. Otherwise the value of
- pid_file_path is used. For backwards compatibility, "%s" in this value is
- replaced by an empty string.
-
-
-Logging
--------
-
-The log_level option and all the various independent logging control options
-have been abolished. In their place there is a single option called
-log_selector. It takes a string argument composed of names preceded by + or -
-characters. These turn on or off the logging of different things. For example:
-
- log_selector = +arguments -retry_defer
-
-The optional logging items (defaults marked *) are:
-
- address_rewrite address rewriting
- all_parents all parents in => lines
- arguments exim arguments
- *connection_reject connection rejections
- *delay_delivery immediate delivery delayed (message queued)
- delivery_size add S=nnn to delivery lines
- *dnslist_defer defers of DNS list (aka RBL) lookups
- incoming_interface incoming interface on <= lines
- incoming_port incoming port on <= lines
- *lost_incoming_connection as it says (includes timeouts)
- *queue_run start and end queue runs
- received_sender sender on <= lines
- received_recipients recipients on <= lines
- *retry_defer "retry time not reached"
- sender_on_delivery add sender to => lines
- *size_reject rejection because too big
- *skip_delivery "message is frozen"
- smtp_confirmation SMTP confirmation on <= lines
- smtp_connection SMTP connections
- smtp_protocol_error SMTP protocol errors
- smtp_syntax_error SMTP syntax errors
- subject contents of Subject: on <= lines
- *tls_cipher TLS cipher on <= lines
- tls_peerdn TLS peer DN on <= lines
-
- all all of the above
-
-"retry time not reached" is always omitted from individual message logs after
-the first delivery attempt.
-
-The log line "error message sent to" has been abolished, because the R= item on
-the incoming message line gives the relationship between the original message
-and the bounce.
-
-The logging options that have been abolished are: log_all_parents,
-log_arguments, log_incoming_port, log_interface, log_ip_options,
-log_level, log_queue_run_level, log_received_sender, log_received_recipients,
-log_rewrites, log_sender_on_delivery, log_smtp_confirmation,
-log_smtp_connections, log_smtp_syntax_errors, log_subject, tls_log_cipher,
-tls_log_peerdn.
-
-
-Debugging
----------
-
-The debug_level option has been removed. The -dm option has been removed. The
--df option has also be removed, along with its related build-time option
-STDERR_FILE. (To debug inetd usage, an auxiliary script should be used.)
-
-The -d option has been reworked. It no longer takes a debug level number
-argument, but instead takes a list of debugging names, each preceded by + or -
-to turn on or off individual sets of debugging messages.
-
-. The -v option now shows just the SMTP dialog and any log lines.
-
-. -d with no argument gives a lot of standard debugging data. This is in effect
- the equivalent of the old -d9, the thing you ask people to set for an initial
- debugging test.
-
-. -d+x adds debugging option x to the default set
- -d-x removes debugging option x from the default set
- -d-all+x leaves only debugging option x
-
-The available debugging names are:
-
- acl ACL interpretation
- auth authenticators
- deliver general delivery logic
- dns DNS lookups (see also resolver)
- dnsbl DNS black list (aka RBL) code
- exec arguments for execv() calls
- filter filter handling
- hints_lookup hints data lookups
- host_lookup all types of name->IP address handling
- ident ident lookup
- interface lists of local interfaces
- lists matching things in lists
- load system load checks
- lookup general lookup code and all lookups
- memory memory handling (replaces the old -dm)
- process_info setting info for the process log
- queue_run queue runs
- receive general message reception logic
- resolver turn on the DNS resolver's debugging output; goes to stdout
- retry retry handling
- rewrite rewriting
- route address routing
- tls TLS logic
- transport transports
- uid changes of uid/gid and looking up uid/gid
- verify address verification logic
-
- all all of the above, and also -v
-
-The default (-d with no argument) includes all of the above, plus -v, with the
-exception of filter, interface, load, memory, and resolver. Some debugging
-output always happens unconditionally whenever any debugging is selected. This
-includes some initial output and every log line.
-
--d without any value was previously allowed for non-admin users because it used
-to be synonymous with -v. In Exim 4, non-admin users may use -v, but not -d.
-
-If the debug_print option is set in any driver, it produces output whenever any
-debugging is selected, or if -v is used.
-
-
-Local Scan Function
--------------------
-
-For customized message scanning, you can now supply a C function that is linked
-into the Exim binary. The function is called local_scan(), and it is called
-when Exim has received a message, but has not yet sent a final
-acknowledgement to the sender. This applies to all messages, whether local or
-remote, SMTP or not.
-
-From within your function you can inspect the message, change the recipients,
-add or remove headers, and tell Exim whether to accept or reject the message.
-
-The manual contains the specification of the API for this function.
-
-
-String Expansion
-----------------
-
-. The lookup feature that allowed for subkeys using the syntax
-
- ${lookup {key:subkey} type {data...
-
- has been abolished (a) because the effect can be achieved using ${extract,
- and (b) because in non-lsearch lookups, a colon can be a valid character in a
- key.
-
-. When a string key is used in a ${extract expansion item, it is now handled
- case-insensitively.
-
-. A new expansion variable called $tod_epoch gives the time as a single decimal
- number representing the number of seconds from the start of the Unix epoch.
-
-. There's a new expansion operator that can turn numbers into base 62, for
- example, ${base62:$tod_epoch}.
-
-. ${extract{number} now recognizes a negative number as a request to count
- fields from the right.
-
-. There's a new expansion feature for reading files:
-
- ${readfile{/some/file}{eolstring}}
-
- The contents of the file replace the item. If {eolstring} is present (it's
- optional) any newlines in the file are replaced by that string.
-
-. There's a new expansion feature for running commands:
-
- ${run{command args}{yes}{no}}
-
- Like all the other conditional items, the {yes} and {no} strings are
- optional. Omitting both is equivalent to {$value}. The standard output of the
- command is put into $value if the command succeeds (returns a zero code). The
- value of the code itself is put into $runrc, and this remains set afterwards,
- so in a filter file you can do things like
-
- if "${run{x y z}{}}$runrc" is 1 then ...
- elsif $runrc is 2 then ...
-
- As in other command executions from Exim, a shell is not used by default.
- If you want a shell, you must explicitly code it.
-
-. The redirect router has options for forbidding ${readfile and ${run in
- filters.
-
-. A feature is provided to suppress expansion of part of a string. Any
- characters between two occurrences of \N are copied to the output string
- verbatim. This is particularly useful for protecting regular expressions from
- unwanted expansion effects. For example:
-
- queue_smtp_domains = ! \N^ten-\d+\.testing\.com$\N
-
- Without \N the \ and $ characters in the regex would have to be escaped.
-
-. Radius authentication is supported in a similar way to PAM. You must set
- RADIUS_CONFIG_FILE in Local/Makefile to specify the location of the Radius
- client configuration file. Then you can use expansions such as
-
- server_condition = ${if radius{arguments}{yes}{no}}
-
-. User authentication can now also be done by attempting to bind to an LDAP
- server. The syntax is again similar to PAM and Radius.
-
- server_condition = ${if ldapauth{ldap query}{yes}{no}}
-
- A user and password are required to be supplied with the query. No actual
- data is looked up; Exim just does a bind to the LDAP server and sets the
- condition according to the result. Here's an example of an SMTP
- authenticator:
-
- login:
- driver = plaintext
- public_name = LOGIN
- server_prompts = "Username:: : Password::"
- server_condition = ${if ldapauth \
- {user="uid=${quote_ldap:$1},ou=people,o=example.org" pass="$2" \
- ldap://ldap.example.org/}{yes}{no}}
- server_set_id = uid=$1,ou=people,o=example.org
-
-
-
-Security
---------
-
-Exim 3 could be run in a variety of ways as far as security was concerned. This
-has all been simplified in Exim 4. Exim dropped the use of seteuid() in
-most places. But recent (2020-10/2021-04) vulnerabilities forced us to
-re-introduce seteuid() for opening the database files (hint files) as secure as
-possible. For future (>= 4.95) versions we work on a solution that
-does not need the seteuid call.
-
-. A UID and GID are required to be specified when Exim is compiled. They can be
- now specified by name as well as by number, so the relevant options are now
- called EXIM_USER and EXIM_GROUP. If you really feel you have to run Exim as
- root, you can specify root here, but it is not recommended.
-
-. The "security" option has been abolished. Exim always releases its root
- privilege when it can. In a conventional configuration, that means when it is
- receiving a message, when it is delivering a message, when it is running a
- queryprogram router, and when it is obeying users' filter files (and system
- filters if it has been given a user for that purpose).
-
-. One important change is that Exim 4 runs as root while routing addresses for
- delivery. Exim 3 used seteuid() to give up privilege temporarily while
- routing. Apart from the unliked use of seteuid(), this sometimes gave rise to
- permissions problems on configuration files.
-
-. However, Exim still runs as the Exim user while receiving messages, and
- therefore while using the routing logic for verifying at SMTP time.
-
-. There is a new option called deliver_drop_privilege. If this is set, Exim
- gives up its privilege right at the start of a delivery process, and runs the
- entire delivery as the Exim user. This is the same action that used to be
- requested by setting security=unprivileged.
-
-
-Hints Databases
----------------
-
-. A single "misc" hints database is now used for ETRN and host serialization.
- There have been appropriate consequential changes to the utilities for
- managing the hints.
-
-. The exim_tidydb -f option has been abolished. A full tidy is now always done
- (it hasn't proved to be very expensive).
-
-
-The run time Configuration File
-------------------------------
-
-. The format of the configuration file has changed. Instead of using "end" to
- terminate sections, it now uses "begin <name>" to start sections. This means
- that the sections, apart from the first, may appear in any order.
-
-. You can now include other files inside Exim run time configuration files, by
- using this syntax:
-
- .include <file name>
-
-. Quotes round the file name are optional. Includes may be nested to any depth,
- but remember that Exim reads its configuration file often. The processing of
- .include happens early, at a physical line level, so, like comment lines, it
- can be used in the middle of an options setting, for example:
-
- hosts_lookup = a.b.c \
- .include /some/file
-
- Include processing happens _before_ macro processing. Its effect is simply to
- process the lines of the file as if they occurred inline where the .include
- appears.
-
-. A macro at the start of a configuration line can now turn the line into an
- empty line or a comment line. This applies to _logical_ input lines, that is,
- after any concatenations have been done.
-
-
-Format of spool files
----------------------
-
-. -local_scan is used in spool files to record the value of $local_scan_data,
- the string returned from the locally-provided local_scan() function.
-
-
-Renamed Options
----------------
-
-Some options have been renamed, to make their function clearer, or for
-consistency.
-
-. receiver_unqualified_hosts has been renamed as recipient_unqualified_hosts.
- I'm going to use "recipient" everywhere in future.
-
-. helo_verify has become helo_verify_hosts.
-
-. remote_sort has become remote_sort_domains.
-
-. In the appendfile and pipe transports, "prefix" and "suffix" have become
- "message_prefix" and "message_suffix". In the generic router options,
- "prefix" and "suffix" have become "local_part_prefix" and "local_part_suffix".
-
-
-Miscellaneous
--------------
-
-. ETRN serialization now uses a double fork, so that an Exim process (detached
- from the original input process) can wait for the command to finish. This
- means that it works whatever command ETRN causes to run. (Previously it
- worked only if ETRN ran "exim -Rxxx".)
-
-. For incoming messages, the server's port number is preserved, and is
- available in $interface_port. The privileged option -oMi can be used to
- set this value.
-
-. The -Mmd option (to mark addresses delivered) now operates in a
- case-sensitive manner.
-
-. Checks for duplicate deliveries are now case-sensitive in the local part.
-
-. The number of situations where Exim panics has been reduced. For example,
- expansion failures for the "domains" or "local_parts" options in a router now
- cause deferral instead of a panic.
-
-. EXPN no longer attempts to distinguish local and remote addresses (but you
- can cause it to be rejected for certain arguments in the ACL).
-
-. accept_timeout has been renamed as receive_timeout, to match
- smtp_receive_timeout.
-
-. The ability to check an ident value as part of an item in a host list has
- been removed.
-
-. The reject log shows a message's headers only if the rejection happens after
- the SMTP DATA command (because they aren't available for earlier checks). The
- sender, and up to five recipients are listed in Envelope-from: and
- Envelope-to: header lines. After the headers, a line of separator characters
- is output. Separators are no longer used for other reject log entries.
-
-. Because header checks are now done as part of ACLs, they now apply only to
- SMTP input.
-
-. The port number on SMTP connections is now logged in the format [aaaa]:ppp
- where aaaa is an IP address and ppp is a port, instead of in the format
- [aaaa.ppp] because the former format causes some software to complain about
- bad IP addresses.
-
-. The -oMa and -oMi options can now use the [aaaa]:ppp notation to set a port
- number, but they still also recognize the aaaa.ppp notation.
-
-. The build-time option HAVE_AUTH is abolished. Exim automatically includes
- authentication code if any authenticators are configured.
-
-. The nobody_user and nobody_group options have been abolished.
-
-. The $message_precedence variable has been abolished. The value is now
- available as $h_precedence:.
-
-. There's a new utility script called exim_checkaccess which packages up a call
- to Exim with the -bh option, for access control checking. The syntax is
-
- exim_checkaccess <IP address> <email address> [exim options]
-
- It runs "exim -bh <IP address>", does the SMTP dialogue, tests the result and
- outputs either "accepted" or "Rejected" and the SMTP response to the RCPT TO
- command. The sender is <> by default, but can be changed by the use of the
- -f option.
-
-. The default state of Exim is now to forbid domain literals. For this reason,
- the option that changes this has been renamed as allow_domain_literals.
-
-. The dns_check_names boolean option has been abolished. Checking is now turned
- off by unsetting dns_check_names_pattern.
-
-. The errors_address and freeze_tell_mailmaster options have been abolished. In
- their place there is a new option called freeze_tell, which can be set to a
- list of addresses. A message is sent to these addresses whenever a message is
- frozen - with the exception of failed bounce messages (this is not changed).
-
-. The message_size_limit_count_recipients option has been abolished on the
- grounds that it was a failed experiment.
-
-. The very-special-purpose X rewrite flag has been abolished. The facility it
- provided can now be done using the features of ACLs.
-
-. The timestamps_utc option has been abolished. The facility is now provided by
- setting timezone = utc.
-
-. The value of remote_max_parallel now defaults to 2.
-
-. ignore_errmsg_errors has been abolished. The effect can be achieved by
- setting ignore_bounce_errors_after = 0s. This option has been renamed from
- ignore_errmsg_errors_after to make its function clearer. The default value
- for ignore_bounce_errors_after is now 10w (10 weeks - i.e. likely to be
- longer than any other timeouts, thereby disabling the facility).
-
-. The default for message_size_limit is now 50M as a guard against DoS attacks.
-
-. The -qi option does only initial (first time) deliveries. This can be helpful
- if you are injecting message onto the queue using -odq and want a queue
- runner just to process new messages. You can also use -qqi if you want.
-
-. Rewriting and retry patterns are now anything that can be single address list
- items. They are processed by the same code, and are therefore expanded before
- the matching takes place. Regular expressions must be suitably quoted. These
- patterns may now be enclosed in double quotes so that white space may be
- included. Normal quote processing applies.
-
-. Some scripts were built in the util directory, which was a mistake, because
- they might be different for different platforms. Everything that is built is
- now built in the build directory. The util directory just contains a couple
- of scripts that are not modified at build time.
-
-. The installation script now installs the Exim binary as exim-v.vv-bb (where
- v.vv is the version number and bb is the build number), and points a symbolic
- link called "exim" to this binary. It does this in an atomic way so that
- there is no time when "exim" is non-existent. The script is clever enough to
- cope with an existing non-symbolic-link binary, converting it to the new
- scheme automatically (and atomically).
-
-. When installing utilities, Exim now uses cp instead of mv to add .O to the
- old ones, in order to preserve the permissions.
-
-. If the installation script is installing the default configuration, and
- /etc/aliases does not exist, the script installs a default version. This does
- not actually contain any aliases, but it does contain comments about ones
- that should be created. A warning is output to the user.
-
-. A delay warning message is not sent if all the addresses in a message get a
- "retry time not reached" error. Exim waits until a delivery is actually
- attempted, so as to be able to give a more informative message.
-
-. The existence of the three options deliver_load_max, queue_only_load, and
- deliver_queue_load_max was confusing, because their function overlapped. The
- first of them has been abolished. We are left with
-
- queue_only_load no immediate delivery if load is high when
- message arrives
- deliver_queue_load_max no queued delivery if load is too high
-
-. The ability to edit message bodies (-Meb and the Eximon menu item) has been
- removed, on the grounds that it is bad practice to do this.
-
-. Eximstats is now Steve Campbell's patched version, which displays sizes in K
- and M and G, and can optionally generate HTML.
-
-. If bounce_sender_authentication is set to an email address, this address is
- used in an AUTH option of the MAIL command when sending bounce messages, if
- authentication is being used. For example, if you set
-
- bounce_sender_authentication = mailer-daemon@your.domain
-
- a bounce message will be sent over an authenticated connection using
-
- MAIL FROM:<> AUTH=mailer-daemon@your.domain
-
-. untrusted_set_sender has changed from a boolean to an address pattern. It
- permits untrusted users to set sender addresses that match the pattern. Like
- all address patterns, it is expanded. The identity of the user is in
- $sender_ident, so you can, for example, restrict users to setting senders
- that start with their login ids by setting
-
- untrusted_set_sender = ^$sender_ident-
-
- The effect of the previous boolean can be achieved by setting the value to *.
- This option applies to all forms of local input.
-
-. The always_bcc option has been abolished. If an incoming message has no To:
- or Cc: headers, Exim now always adds an empty Bcc: line. This makes the
- message valid for RFC 822 (sic). In time, this can be removed, because RFC
- 2822 does not require there to be a recipient header.
-
-. ACTION_OUTPUT=no is now the default in the Exim monitor.
-
-. dns_ipv4_lookup has changed from a boolean into a domain list, and it now
- applies only to those domains. Setting this option does not stop Exim from
- making IPv6 calls: if an MX lookup returns AAAA records, Exim will use them.
- What it does is to stop Exim looking for AAAA records explicitly.
-
-. The -G option is ignored (another Sendmail thing).
-
-. If no_bounce_return_message is set, the original message is not included in
- bounce messages. If you want to include additional information in the bounce
- message itself, you can use the existing errmsg_file and errmsg_text
- facilities.
-
-. -bdf runs the daemon in the foreground (i.e. not detached from the terminal),
- even when no debugging is requested.
-
-. Options for changing Exim's behaviour on receiving IPv4 options have been
- abolished. Exim now always refuses calls that set these options, and logs the
- incident. The abolished options are kill_ip_options, log_ip_options, and
- refuse_ip_options.
-
-. The pattern for each errors_copy entry is now matched as an item in an
- address list.
-
-. A number of options and variables that used the word "errmsg" have been
- changed to use "bounce" instead, because it seems that "bounce message" is
- now a reasonably well-understood term. I used it in the book and am now using
- it in the manual; it's a lot less cumbersome than "delivery error
- notification message". The changes are:
-
- $errmsg_recipient => $bounce_recipient
- errmsg_file => bounce_message_file
- errmsg_text => bounce_message_text
- ignore_errmsg_errors_after => ignore_bounce_errors_after
-
- For consistency, warnmsg_file has been changed to warn_message_file. However,
- the two variables $warnmsg_delay and $warnmsg_recipients are unchanged.
-
- The hide_child_in_errmsg option has not changed, because it applies to both
- bounce and delay warning messages.
-
-. smtp_accept_max_per_host is now an expanded string, so it can be varied on
- a per-host basis. However, because this test happens in the daemon before it
- forks, the expansion should be kept as simple as possible (e.g. just inline
- tests of $sender_host_address).
-
-. The retry rules can now recognize the error "auth_failed", which happens when
- authentication is required, but cannot be done.
-
-. There's a new option called local_sender_retain which can be set if
- no_local_from_check is set. It causes Sender: headers to be retained in
- locally-submitted messages.
-
-. The -dropcr command line option now turns CRLF into LF, and leaves isolated
- CRs alone. Previously it simply dropped _all_ CR characters. There is now
- also a drop_cr main option which, if turned on, assumes -dropcr for all
- non-SMTP input.
-
-
-Removal of Obsolete Things
---------------------------
-
-. The obsolete values "fail_soft" and "fail_hard" for the "self" option have
- been removed.
-
-. The obsolete "log" command has been removed from the filter language.
-
-. "service" was an obsolete synonym for "port" when specifying IP port numbers.
- It has been removed.
-
-. The obsolete option collapse_source_routes has been removed. It has done
- nothing since release 3.10.
-
-. The obsolete from_hack option in appendfile and pipe transports has been
- removed.
-
-. The obsolete ipv4_address_lookup has been abolished (dns_ipv4_lookup has been
- a synonym for some time, but it's changed - see above).
-
-. The obsolete generic transport options add_headers and remove_headers have
- been abolished. The new names, headers_add and headers_remove, have been
- available for some time.
-
-Philip Hazel
-February 2002
utils: $(EXIM_MONITOR) exicyclog exinext exiwhat \
exigrep eximstats exipick exiqgrep exiqsumm \
- transport-filter.pl convert4r3 convert4r4 \
- exim_checkaccess \
+ transport-filter.pl exim_checkaccess \
exim_dbmbuild exim_dumpdb exim_fixdb exim_tidydb \
exim_lock exim_msgdate exim_id_update
@chmod a+x transport-filter.pl
@echo ">>> transport-filter.pl script built"
-convert4r3: config ../src/convert4r3.src
- @rm -f convert4r3
- @. ./version.sh && sed \
- -e "s?PERL_COMMAND?$(PERL_COMMAND)?" \
- -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \
- -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \
- ../src/convert4r3.src > convert4r3-t
- @mv convert4r3-t convert4r3
- @chmod a+x convert4r3
- @./convert4r3 -v 2>&1 >/dev/null
- @echo ">>> convert4r3 script built"
-
-convert4r4: config ../src/convert4r4.src
- @rm -f convert4r4
- @. ./version.sh && sed \
- -e "s?PERL_COMMAND?$(PERL_COMMAND)?" \
- -e "s?EXIM_RELEASE_VERSION?$${EXIM_RELEASE_VERSION}?" \
- -e "s?EXIM_VARIANT_VERSION?$${EXIM_VARIANT_VERSION}?" \
- ../src/convert4r4.src > convert4r4-t
- @mv convert4r4-t convert4r4
- @chmod a+x convert4r4
- @./convert4r4 -v 2>&1 >/dev/null
- @echo ">>> convert4r4 script built"
-
# These are objects of optional features. They are always compiled, but
# if the corresponding #defines are not set, they wind up empty and
The current edition covers release 4.10 and a few later extensions.
The O'Reilly book about Exim ("Exim The Mail Transfer Agent" by Philip Hazel)
-covers Exim 3, which is now deprecated. Exim 4 has a large number of changes
+covers Exim 3, which is now obsolete. Exim 4 has a large number of changes
from Exim 3, though the basic structure and philosophy remains the same. The
older book may be helpful for the background, but a lot of the detail has
changed, so it is likely to be confusing to newcomers.
+++ /dev/null
-#! PERL_COMMAND
-
-# This is a Perl script that reads an Exim run-time configuration file and
-# checks for settings that were valid prior to release 3.00 but which were
-# obsoleted by that release. It writes a new file with suggested changes to
-# the standard output, and commentary about what it has done to stderr.
-
-# It is assumed that the input is a valid Exim configuration file.
-
-use warnings;
-BEGIN { pop @INC if $INC[-1] eq '.' };
-
-use Getopt::Long;
-use File::Basename;
-
-GetOptions(
- 'version' => sub {
- print basename($0) . ": $0\n",
- "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION\n",
- "perl(runtime): $^V\n";
- exit 0;
- },
-);
-
-##################################################
-# Analyse one line #
-##################################################
-
-# This is called for the main and the driver sections, not for retry
-# or rewrite sections (which are unmodified).
-
-sub checkline{
-my($line) = $_[0];
-
-return "comment" if $line =~ /^\s*(#|$)/;
-return "end" if $line =~ /^\s*end\s*$/;
-
-# Macros are recognized only in the first section of the file.
-
-return "macro" if $prefix eq "" && $line =~ /^\s*[A-Z]/;
-
-# Pick out the name at the start and the rest of the line (into global
-# variables) and return whether the start of a driver or not.
-
-($i1,$name,$i2,$rest) = $line =~ /^(\s*)([a-z0-9_]+)(\s*)(.*?)\s*$/;
-return ($rest =~ /^:/)? "driver" : "option";
-}
-
-
-
-
-##################################################
-# Add transport setting to a director #
-##################################################
-
-# This function adds a transport setting to an aliasfile or forwardfile
-# director if a global setting exists and a local one does not. If neither
-# exist, it adds file/pipe/reply, but not the directory ones.
-
-sub add_transport{
-my($option) = @_;
-
-my($key) = "$prefix$driver.${option}_transport";
-if (!exists $o{$key})
- {
- if (exists $o{"address_${option}_transport"})
- {
- print STDOUT "# >> Option added by convert4r3\n";
- printf STDOUT "${i1}${option}_transport = %s\n",
- $o{"address_${option}_transport"};
- printf STDERR
- "\n%03d ${option}_transport added to $driver director.\n",
- ++$count;
- }
- else
- {
- if ($option eq "pipe" || $option eq "file" || $option eq "reply")
- {
- print STDOUT "# >> Option added by convert4r3\n";
- printf STDOUT "${i1}${option}_transport = address_${option}\n";
- printf STDERR
- "\n%03d ${option}_transport added to $driver director.\n",
- ++$count;
- }
- }
- }
-}
-
-
-
-
-##################################################
-# Negate a list of things #
-##################################################
-
-sub negate {
-my($list) = $_[0];
-
-return $list if ! defined $list;
-
-($list) = $list =~ /^"?(.*?)"?\s*$/s;
-
-# Under Perl 5.005 we can split very nicely at colons, ignoring double
-# colons, like this:
-#
-# @split = split /\s*(?<!:):(?!:)\s*(?:\\\s*)?/s, $list;
-#
-# However, we'd better make this work under Perl 5.004, since there is
-# a lot of that about.
-
-$list =~ s/::/>%%%%</g;
-@split = split /\s*:\s*(?:\\\s*)?/s, $list;
-foreach $item (@split)
- {
- $item =~ s/>%%%%</::/g;
- }
-
-$" = " : \\\n ! ";
-return "! @split";
-}
-
-
-
-
-
-##################################################
-# Skip blank lines #
-##################################################
-
-# This function is called after we have generated no output for an option;
-# it skips subsequent blank lines if the previous line was blank.
-
-sub skipblanks {
-my($i) = $_[0];
-if ($last_was_blank)
- {
- $i++ while $c[$i+1] =~ /^\s*$/;
- }
-return $i;
-}
-
-
-
-
-
-##################################################
-# Get base name of data key #
-##################################################
-
-sub base {
-return "$_[0]" if $_[0] !~ /^(?:d|r|t)\.[^.]+\.(.*)/;
-return $1;
-}
-
-
-
-##################################################
-# Amalgamate accept/reject/reject_except #
-##################################################
-
-# This function amalgamates the three previous kinds of
-# option into a single list, using negation for the middle one if
-# the final argument is "+", or for the outer two if the final
-# argument is "-".
-
-sub amalgamate {
-my($accept,$reject,$reject_except,$name);
-my($last_was_negated) = 0;
-my($join) = "";
-
-$accept = $o{$_[0]};
-$reject = $o{$_[1]};
-$reject_except = $o{$_[2]};
-$name = $_[3];
-
-if ($_[4] eq "+")
- {
- ($accept) = $accept =~ /^"?(.*?)"?\s*$/s if defined $accept;
- $reject = &negate($reject) if defined $reject;
- ($reject_except) = $reject_except =~ /^"?(.*?)"?\s*$/s if defined $reject_except;
- }
-else
- {
- $accept = &negate($accept) if defined $accept;
- ($reject) = $reject =~ /^"?(.*?)"?\s*$/s if defined $reject;
- $reject_except = &negate($reject_except) if defined $reject_except;
- }
-
-print STDOUT "# >> Option rewritten by convert4r3\n";
-print STDOUT "${i1}$name = \"";
-
-if (defined $reject_except)
- {
- print STDOUT "$reject_except";
- $join = " : \\\n ";
- $last_was_negated = ($_[4] ne "+");
- }
-if (defined $reject)
- {
- print STDOUT "$join$reject";
- $join = " : \\\n ";
- $last_was_negated = ($_[4] eq "+");
- }
-if (defined $accept)
- {
- print STDOUT "$join$accept";
- $last_was_negated = ($_[4] ne "+");
- $join = " : \\\n ";
- }
-
-print STDOUT "$join*" if $last_was_negated;
-
-print STDOUT "\"\n";
-
-my($driver_name);
-my($driver_type) = "";
-
-if ($_[0] =~ /^(d|r|t)\.([^.]+)\./ ||
- $_[1] =~ /^(d|r|t)\.([^.]+)\./ ||
- $_[2] =~ /^(d|r|t)\.([^.]+)\./)
- {
- $driver_type = ($1 eq 'd')? "director" : ($1 eq 'r')? "router" : "transport";
- $driver_name = $2;
- }
-
-my($x) = ($driver_type ne "")? " in \"$driver_name\" $driver_type" : "";
-
-my($l0) = &base($_[0]);
-my($l1) = &base($_[1]);
-my($l2) = &base($_[2]);
-
-
-if ($l2 eq "")
- {
- if ($l0 eq "")
- {
- printf STDERR "\n%03d $l1 converted to $name$x.\n", ++$count;
- }
- else
- {
- printf STDERR "\n%03d $l0 and $l1\n amalgamated into $name$x.\n",
- ++$count;
- }
- }
-else
- {
- if ($l1 eq "")
- {
- printf STDERR "\n%03d $l0 and $l2\n amalgamated into $name$x.\n",
- ++$count;
- }
- else
- {
- printf STDERR "\n%03d $l0, $l1 and $l2\n amalgamated into " .
- "$name$x.\n", ++$count;
- }
- }
-}
-
-
-
-
-##################################################
-# Join two lists, if they exist #
-##################################################
-
-sub pair{
-my($l1) = $o{"$_[0]"};
-my($l2) = $o{"$_[1]"};
-
-return $l2 if (!defined $l1);
-return $l1 if (!defined $l2);
-
-($l1) = $l1 =~ /^"?(.*?)"?\s*$/s;
-($l2) = $l2 =~ /^"?(.*?)"?\s*$/s;
-
-return "$l1 : $l2";
-}
-
-
-
-
-##################################################
-# Amalgamate accept/reject/reject_except pairs #
-##################################################
-
-# This is like amalgamate, but it combines pairs of arguments, and
-# doesn't output commentary (easier to write a generic one for the few
-# cases).
-
-sub amalgamatepairs {
-my($accept) = &pair($_[0], $_[1]);
-my($reject) = &pair($_[2], $_[3]);
-my($reject_except) = &pair($_[4], $_[5]);
-my($last_was_negated) = 0;
-my($join) = "";
-
-if ($_[7] eq "+")
- {
- ($accept) = $accept =~ /^"?(.*?)"?\s*$/s if defined $accept;
- $reject = &negate($reject) if defined $reject;
- ($reject_except) = $reject_except =~ /^"?(.*?)"?\s*$/s if defined $reject_except;
- }
-else
- {
- $accept = &negate($accept) if defined $accept;
- ($reject) = $reject =~ /^"?(.*?)"?$/s if defined $reject;
- $reject_except = &negate($reject_except) if defined $reject_except;
- }
-
-print STDOUT "# >> Option rewritten by convert4r3\n";
-print STDOUT "${i1}$_[6] = \"";
-
-if (defined $reject_except)
- {
- print STDOUT "$reject_except";
- $join = " : \\\n ";
- $last_was_negated = ($_[7] ne "+");
- }
-if (defined $reject)
- {
- print STDOUT "$join$reject";
- $join = " : \\\n ";
- $last_was_negated = ($_[7] eq "+");
- }
-if (defined $accept)
- {
- print STDOUT "$join$accept";
- $last_was_negated = ($_[7] ne "+");
- $join = " : \\\n ";
- }
-
-print STDOUT "$join*" if $last_was_negated;
-print STDOUT "\"\n";
-}
-
-
-
-##################################################
-# Amalgamate boolean and exception list(s) #
-##################################################
-
-sub amalgboolandlist {
-my($name,$bool,$e1,$e2) = @_;
-
-print STDOUT "# >> Option rewritten by convert4r3\n";
-if ($bool eq "false")
- {
- printf STDOUT "$i1$name =\n";
- }
-else
- {
- printf STDOUT "$i1$name = ";
- my($n1) = &negate($o{$e1});
- my($n2) = &negate($o{$e2});
- if (!defined $n1 && !defined $n2)
- {
- print STDOUT "*\n";
- }
- elsif (!defined $n1)
- {
- print STDOUT "\"$n2 : \\\n *\"\n";
- }
- elsif (!defined $n2)
- {
- print STDOUT "\"$n1 : \\\n *\"\n";
- }
- else
- {
- print STDOUT "\"$n1 : \\\n $n2 : \\\n *\"\n";
- }
- }
-}
-
-
-
-##################################################
-# Convert mask format #
-##################################################
-
-# This function converts an address and mask in old-fashioned dotted-quad
-# format into an address plus a new format mask.
-
-@byte_list = (0, 128, 192, 224, 240, 248, 252, 254, 255);
-
-sub mask {
-my($address,$mask) = @_;
-my($length) = 0;
-my($i, $j);
-
-my(@bytes) = split /\./, $mask;
-
-for ($i = 0; $i < 4; $i++)
- {
- for ($j = 0; $j <= 8; $j++)
- {
- if ($bytes[$i] == $byte_list[$j])
- {
- $length += $j;
- if ($j != 8)
- {
- for ($i++; $i < 4; $i++)
- {
- $j = 9 if ($bytes[$i] != 0);
- }
- }
- last;
- }
- }
-
- if ($j > 8)
- {
- print STDERR "*** IP mask $mask cannot be converted to /n format. ***\n";
- return "$address/$mask";
- }
- }
-
-if (!defined $masks{$mask})
- {
- printf STDERR "\n%03d IP address mask $mask converted to /$length\n",
- ++$count, $mask, $length;
- $masks{$mask} = 1;
- }
-
-return sprintf "$address/%d", $length;
-}
-
-
-
-
-
-##################################################
-# Main program #
-##################################################
-
-print STDERR "Exim pre-release 3.00 configuration file converter.\n";
-
-$count = 0;
-$seen_helo_accept_junk = 0;
-$seen_hold_domains = 0;
-$seen_receiver_unqualified = 0;
-$seen_receiver_verify_except = 0;
-$seen_receiver_verify_senders = 0;
-$seen_rfc1413_except = 0;
-$seen_sender_accept = 0;
-$seen_sender_accept_recipients = 0;
-$seen_sender_host_accept = 0;
-$seen_sender_host_accept_recipients = 0;
-$seen_sender_host_accept_relay = 0;
-$seen_sender_unqualified = 0;
-$seen_sender_verify_except_hosts = 0;
-$seen_smtp_etrn = 0;
-$seen_smtp_expn = 0;
-$seen_smtp_reserve = 0;
-$semicomma = 0;
-
-# Read the entire file into an array
-
-chomp(@c = <STDIN>);
-
-# First, go through the input and covert any net masks in the old dotted-quad
-# style into the new /n style.
-
-for ($i = 0; $i < scalar(@c); $i++)
- {
- $c[$i] =~
- s"((?:\d{1,3}\.){3}\d{1,3})/((?:\d{1,3}\.){3}\d{1,3})"&mask($1,$2)"eg;
- }
-
-# We now make two more passes over the input. In the first pass, we place all
-# the option values into an associative array. Main options are keyed by their
-# names; options for drivers are keyed by a driver type letter, the driver
-# name, and the option name, dot-separated. In the second pass we modify
-# the options if necessary, and write the output file.
-
-for ($pass = 1; $pass < 3; $pass++)
- {
- $prefix = "";
- $driver = "";
- $last_was_blank = 0;
-
- for ($i = 0; $i < scalar(@c); $i++)
- {
- # Everything after the router section is just copied in pass 2 and
- # ignored in pass 1.
-
- if ($prefix eq "end")
- {
- print STDOUT "$c[$i]\n" if $pass == 2;
- next;
- }
-
- # Analyze the line
-
- $type = &checkline($c[$i]);
-
- # Skip comments in pass 1; copy in pass 2
-
- if ($type eq "comment")
- {
- $last_was_blank = ($c[$i] =~ /^\s*$/)? 1 : 0;
- print STDOUT "$c[$i]\n" if $pass == 2;
- next;
- }
-
- # Skip/copy macro definitions, but must handle continuations
-
- if ($type eq "macro")
- {
- print STDOUT "$c[$i]\n" if $pass == 2;
- while ($c[$i] =~ /\\\s*$/)
- {
- $i++;
- print STDOUT "$c[$i]\n" if $pass == 2;
- }
- $last_was_blank = 0;
- next;
- }
-
- # Handle end of section
-
- if ($type eq "end")
- {
- $prefix = "end"if $prefix eq "r.";
- $prefix = "r." if $prefix eq "d.";
- $prefix = "d." if $prefix eq "t.";
- $prefix = "t." if $prefix eq "";
- print STDOUT "$c[$i]\n" if $pass == 2;
- $last_was_blank = 0;
- next;
- }
-
- # Handle start of a new driver
-
- if ($type eq "driver")
- {
- $driver = $name;
- print STDOUT "$c[$i]\n" if $pass == 2;
- $last_was_blank = 0;
- $seen_domains = 0;
- $seen_local_parts = 0;
- $seen_senders = 0;
- $seen_mx_domains = 0;
- $seen_serialize = 0;
- next;
- }
-
- # Handle definition of an option
-
- if ($type eq "option")
- {
- # Handle continued strings
-
- if ($rest =~ /^=\s*".*\\$/)
- {
- for (;;)
- {
- $rest .= "\n$c[++$i]";
- last unless $c[$i] =~ /(\\\s*$|^\s*#)/;
- }
- }
-
- # Remove any terminating commas and semicolons in pass 2
-
- if ($pass == 2 && $rest =~ /[;,]\s*$/)
- {
- $rest =~ s/\s*[;,]\s*$//;
- if (!$semicomma)
- {
- printf STDERR
- "\n%03d Terminating semicolons and commas removed from driver " .
- "options.\n", ++$count;
- $semicomma = 1;
- }
- }
-
- # Convert all booleans to "x = true/false" format, but save the
- # original so that it can be reproduced unchanged for options that
- # are not of interest.
-
- $origname = $name;
- $origrest = $rest;
-
- if ($name =~ /^not?_(.*)/)
- {
- $name = $1;
- $rest = "= false";
- }
- elsif ($rest !~ /^=/)
- {
- $rest = "= true";
- }
-
- # Set up the associative array key, and get rid of the = on the data
-
- $key = ($prefix eq "")? "$name" : "$prefix$driver.$name";
- ($rest) = $rest =~ /^=\s*(.*)/s;
-
- # Create the associative array of values in pass 1
-
- if ($pass == 1)
- {
- $o{$key} = $rest;
- }
-
- # In pass 2, test for interesting options and do the necessary; copy
- # all the rest.
-
- else
- {
- ########## Global configuration ##########
-
- # These global options are abolished
-
- if ($name eq "address_directory_transport" ||
- $name eq "address_directory2_transport" ||
- $name eq "address_file_transport" ||
- $name eq "address_pipe_transport" ||
- $name eq "address_reply_transport")
- {
- ($n2) = $name =~ /^address_(.*)/;
- printf STDERR "\n%03d $name option deleted.\n", ++$count;
- printf STDERR " $n2 will be added to appropriate directors.\n";
- $i = &skipblanks($i);
- next;
- }
-
- # This debugging option is abolished
-
- elsif ($name eq "sender_verify_log_details")
- {
- printf STDERR "\n%03d $name option deleted.\n", ++$count;
- printf STDERR " (Little used facility abolished.)\n";
- }
-
- # This option has been renamed
-
- elsif ($name eq "check_dns_names")
- {
- $origname =~ s/check_dns/dns_check/;
- print STDOUT "# >> Option rewritten by convert4r3\n";
- print STDOUT "$i1$origname$i2$origrest\n";
- printf STDERR "\n%03d check_dns_names renamed as dns_check_names.\n",
- ++$count;
- }
-
- # helo_accept_junk_nets is abolished
-
- elsif ($name eq "helo_accept_junk_nets" ||
- $name eq "helo_accept_junk_hosts")
- {
- if (!$seen_helo_accept_junk)
- {
- &amalgamate("helo_accept_junk_nets", "",
- "helo_accept_junk_hosts", "helo_accept_junk_hosts", "+");
- $seen_helo_accept_junk = 1;
- }
- else
- {
- $i = &skipblanks($i);
- next;
- }
- }
-
- # helo_verify_except_{hosts,nets} are abolished, and helo_verify
- # is now a host list instead of a boolean.
-
- elsif ($name eq "helo_verify")
- {
- &amalgboolandlist("helo_verify", $rest, "helo_verify_except_hosts",
- "helo_verify_except_nets");
- printf STDERR "\n%03d helo_verify converted to host list.\n",
- ++$count;
- }
- elsif ($name eq "helo_verify_except_hosts" ||
- $name eq "helo_verify_except_nets")
- {
- $i = &skipblanks($i);
- next;
- }
-
- # helo_verify_nets was an old synonym for host_lookup_nets; only
- # one of them will be encountered. Change to a new name.
-
- elsif ($name eq "helo_verify_nets" ||
- $name eq "host_lookup_nets")
- {
- print STDOUT "# >> Option rewritten by convert4r3\n";
- print STDOUT "${i1}host_lookup$i2$origrest\n";
- printf STDERR "\n%03d $name renamed as host_lookup.\n", ++$count;
- }
-
- # hold_domains_except is abolished; add as negated items to
- # hold_domains.
-
- elsif ($name eq "hold_domains_except" ||
- $name eq "hold_domains")
- {
- if ($seen_hold_domains) # If already done with these
- { # omit, and following blanks.
- $i = &skipblanks($i);
- next;
- }
- $seen_hold_domains = 1;
-
- if (exists $o{"hold_domains_except"})
- {
- &amalgamate("hold_domains", "hold_domains_except", "",
- "hold_domains", "+");
- }
- else
- {
- print STDOUT "$i1$origname$i2$origrest\n";
- }
- }
-
- # ignore_fromline_nets is renamed as ignore_fromline_hosts
-
- elsif ($name eq "ignore_fromline_nets")
- {
- $origname =~ s/_nets/_hosts/;
- print STDOUT "# >> Option rewritten by convert4r3\n";
- print STDOUT "$i1$origname$i2$origrest\n";
- printf STDERR
- "\n%03d ignore_fromline_nets renamed as ignore_fromline_hosts.\n",
- ++$count;
- }
-
- # Output a warning for message filters with no transports set
-
- elsif ($name eq "message_filter")
- {
- print STDOUT "$i1$origname$i2$origrest\n";
-
- if (!exists $o{"message_filter_directory_transport"} &&
- !exists $o{"message_filter_directory2_transport"} &&
- !exists $o{"message_filter_file_transport"} &&
- !exists $o{"message_filter_pipe_transport"} &&
- !exists $o{"message_filter_reply_transport"})
- {
- printf STDERR
- "\n%03d message_filter is set, but no message_filter transports "
- . "are defined.\n"
- . " If your filter generates file or pipe deliveries, or "
- . "auto-replies,\n"
- . " you will need to define "
- . "message_filter_{file,pipe,reply}_transport\n"
- . " options, as required.\n", ++$count;
- }
- }
-
- # queue_remote_except is abolished, and queue_remote is replaced by
- # queue_remote_domains, which is a host list.
-
- elsif ($name eq "queue_remote")
- {
- &amalgboolandlist("queue_remote_domains", $rest,
- "queue_remote_except", "");
- printf STDERR
- "\n%03d queue_remote converted to domain list queue_remote_domains.\n",
- ++$count;
- }
- elsif ($name eq "queue_remote_except")
- {
- $i = &skipblanks($i);
- next;
- }
-
- # queue_smtp_except is abolished, and queue_smtp is replaced by
- # queue_smtp_domains, which is a host list.
-
- elsif ($name eq "queue_smtp")
- {
- &amalgboolandlist("queue_smtp_domains", $rest,
- "queue_smtp_except", "");
- printf STDERR
- "\n%03d queue_smtp converted to domain list queue_smtp_domains.\n",
- ++$count;
- }
- elsif ($name eq "queue_smtp_except")
- {
- $i = &skipblanks($i);
- next;
- }
-
- # rbl_except_nets is replaced by rbl_hosts
-
- elsif ($name eq "rbl_except_nets")
- {
- &amalgamate("", "rbl_except_nets", "", "rbl_hosts", "+");
- }
-
- # receiver_unqualified_nets is abolished
-
- elsif ($name eq "receiver_unqualified_nets" ||
- $name eq "receiver_unqualified_hosts")
- {
- if (!$seen_receiver_unqualified)
- {
- &amalgamate("receiver_unqualified_nets", "",
- "receiver_unqualified_hosts", "receiver_unqualified_hosts", "+");
- $seen_receiver_unqualified = 1;
- }
- else
- {
- $i = &skipblanks($i);
- next;
- }
- }
-
- # receiver_verify_except_{hosts,nets} are replaced by
- # receiver_verify_hosts.
-
- elsif ($name eq "receiver_verify_except_hosts" ||
- $name eq "receiver_verify_except_nets")
- {
- if (!$seen_receiver_verify_except)
- {
- &amalgboolandlist("receiver_verify_hosts", "true",
- "receiver_verify_except_hosts", "receiver_verify_except_nets");
- printf STDERR
- "\n%03d receiver_verify_except_{hosts,nets} converted to " .
- "receiver_verify_hosts.\n",
- ++$count;
- $seen_receiver_verify_except = 1;
- }
- else
- {
- $i = &skipblanks($i);
- next;
- }
- }
-
- # receiver_verify_senders_except is abolished
-
- elsif ($name eq "receiver_verify_senders" ||
- $name eq "receiver_verify_senders_except")
- {
- if (defined $o{"receiver_verify_senders_except"})
- {
- if (!$seen_receiver_verify_senders)
- {
- &amalgamate("receiver_verify_senders",
- "receiver_verify_senders_except", "",
- "receiver_verify_senders", "+");
- $seen_receiver_verify_senders = 1;
- }
- else
- {
- $i = &skipblanks($i);
- next;
- }
- }
- else
- {
- print STDOUT "$i1$origname$i2$origrest\n";
- }
- }
-
- # rfc1413_except_{hosts,nets} are replaced by rfc1413_hosts.
-
- elsif ($name eq "rfc1413_except_hosts" ||
- $name eq "rfc1413_except_nets")
- {
- if (!$seen_rfc1413_except)
- {
- &amalgboolandlist("rfc1413_hosts", "true",
- "rfc1413_except_hosts", "rfc1413_except_nets");
- printf STDERR
- "\n%03d rfc1413_except_{hosts,nets} converted to rfc1413_hosts.\n",
- ++$count;
- $seen_rfc1413_except = 1;
- }
- else
- {
- $i = &skipblanks($i);
- next;
- }
- }
-
- # sender_accept and sender_reject_except are abolished
-
- elsif ($name eq "sender_accept" ||
- $name eq "sender_reject")
- {
- if (!$seen_sender_accept)
- {
- &amalgamate("sender_accept", "sender_reject",
- "sender_reject_except", "sender_reject", "-");
- $seen_sender_accept = 1;
- }
- else
- {
- $i = &skipblanks($i);
- next;
- }
- }
-
- # sender_accept_recipients is also abolished; sender_reject_except
- # also used to apply to this, so we include it here as well.
-
- elsif ($name eq "sender_accept_recipients" ||
- $name eq "sender_reject_recipients")
- {
- if (!$seen_sender_accept_recipients)
- {
- &amalgamate("sender_accept_recipients", "sender_reject_recipients",
- "sender_reject_except", "sender_reject_recipients", "-");
- $seen_sender_accept_recipients = 1;
- }
- else
- {
- $i = &skipblanks($i);
- next;
- }
- }
-
- # sender_reject_except must be removed
-
- elsif ($name eq "sender_reject_except")
- {
- $i = &skipblanks($i);
- next;
- }
-
- # sender_{host,net}_{accept,reject}[_except] all collapse into
- # host_reject.
-
- elsif ($name eq "sender_host_accept" ||
- $name eq "sender_net_accept" ||
- $name eq "sender_host_reject" ||
- $name eq "sender_net_reject")
- {
- if (!$seen_sender_host_accept)
- {
- &amalgamatepairs("sender_host_accept", "sender_net_accept",
- "sender_host_reject", "sender_net_reject",
- "sender_host_reject_except", "sender_net_reject_except",
- "host_reject", "-");
- printf STDERR "\n%03d sender_{host,net}_{accept,reject} and " .
- "sender_{host_net}_reject_except\n" .
- " amalgamated into host_reject.\n", ++$count;
- $seen_sender_host_accept = 1;
- }
- else
- {
- $i = &skipblanks($i);
- next;
- }
- }
-
- # sender_{host,net}_{accept,reject}_recipients all collapse into
- # host_reject_recipients.
-
- elsif ($name eq "sender_host_accept_recipients" ||
- $name eq "sender_net_accept_recipients" ||
- $name eq "sender_host_reject_recipients" ||
- $name eq "sender_net_reject_recipients")
- {
- if (!$seen_sender_host_accept_recipients)
- {
- &amalgamatepairs("sender_host_accept_recipients",
- "sender_net_accept_recipients",
- "sender_host_reject_recipients",
- "sender_net_reject_recipients",
- "sender_host_reject_except", "sender_net_reject_except",
- "host_reject_recipients", "-");
- printf STDERR "\n%03d sender_{host,net}_{accept,reject}_recipients"
- . "\n and sender_{host_net}_reject_except"
- . "\n amalgamated into host_reject_recipients.\n", ++$count;
- $seen_sender_host_accept_recipients = 1;
- }
- else
- {
- $i = &skipblanks($i);
- next;
- }
- }
-
- # sender_{host,net}_reject_except must be removed
-
- elsif ($name eq "sender_host_reject_except" ||
- $name eq "sender_net_reject_except")
- {
- $i = &skipblanks($i);
- next;
- }
-
- # sender_{host,net}_{accept,reject}_relay all collapse into
- # host_accept_relay.
-
- elsif ($name eq "sender_host_accept_relay" ||
- $name eq "sender_net_accept_relay" ||
- $name eq "sender_host_reject_relay" ||
- $name eq "sender_net_reject_relay")
- {
- if (!$seen_sender_host_accept_relay)
- {
- &amalgamatepairs("sender_host_accept_relay",
- "sender_net_accept_relay",
- "sender_host_reject_relay",
- "sender_net_reject_relay",
- "sender_host_reject_relay_except",
- "sender_net_reject_relay_except",
- "host_accept_relay", "+");
- printf STDERR "\n%03d sender_{host,net}_{accept,reject}_relay"
- . "\n and sender_{host_net}_reject_relay_except"
- . "\n amalgamated into host_accept_relay.\n", ++$count;
- $seen_sender_host_accept_relay = 1;
- }
- else
- {
- $i = &skipblanks($i);
- next;
- }
- }
-
- # sender_{host,net}_reject_relay_except must be removed
-
- elsif ($name eq "sender_host_reject_relay_except" ||
- $name eq "sender_net_reject_relay_except")
- {
- $i = &skipblanks($i);
- next;
- }
-
-
- # sender_unqualified_nets is abolished
-
- elsif ($name eq "sender_unqualified_nets" ||
- $name eq "sender_unqualified_hosts")
- {
- if (!$seen_sender_unqualified)
- {
- &amalgamate("sender_unqualified_nets", "",
- "sender_unqualified_hosts", "sender_unqualified_hosts", "+");
- $seen_sender_unqualified = 1;
- }
- else
- {
- $i = &skipblanks($i);
- next;
- }
- }
-
- # sender_verify_except_{hosts,nets} are replaced by sender_verify_hosts.
-
- elsif ($name eq "sender_verify_except_hosts" ||
- $name eq "sender_verify_except_nets")
- {
- if (!$seen_sender_verify_except_hosts)
- {
- &amalgboolandlist("sender_verify_hosts", "true",
- "sender_verify_except_hosts", "sender_verify_except_nets");
- printf STDERR
- "\n%03d sender_verify_except_{hosts,nets} converted to " .
- "sender_verify_hosts.\n",
- ++$count;
- $seen_sender_verify_except_hosts = 1;
- }
- else
- {
- $i = &skipblanks($i);
- next;
- }
- }
-
- # smtp_etrn_nets is abolished
-
- elsif ($name eq "smtp_etrn_nets" ||
- $name eq "smtp_etrn_hosts")
- {
- if (!$seen_smtp_etrn)
- {
- &amalgamate("smtp_etrn_nets", "",
- "smtp_etrn_hosts", "smtp_etrn_hosts", "+");
- $seen_smtp_etrn = 1;
- }
- else
- {
- $i = &skipblanks($i);
- next;
- }
- }
-
- # smtp_expn_nets is abolished
-
- elsif ($name eq "smtp_expn_nets" ||
- $name eq "smtp_expn_hosts")
- {
- if (!$seen_smtp_expn)
- {
- &amalgamate("smtp_expn_nets", "",
- "smtp_expn_hosts", "smtp_expn_hosts", "+");
- $seen_smtp_expn = 1;
- }
- else
- {
- $i = &skipblanks($i);
- next;
- }
- }
-
- # This option has been renamed
-
- elsif ($name eq "smtp_log_connections")
- {
- $origname =~ s/smtp_log/log_smtp/;
- print STDOUT "# >> Option rewritten by convert4r3\n";
- print STDOUT "$i1$origname$i2$origrest\n";
- printf STDERR "\n%03d smtp_log_connections renamed as " .
- "log_smtp_connections.\n",
- ++$count;
- }
-
- # smtp_reserve_nets is abolished
-
- elsif ($name eq "smtp_reserve_nets" ||
- $name eq "smtp_reserve_hosts")
- {
- if (!$seen_smtp_reserve)
- {
- &amalgamate("smtp_reserve_nets", "",
- "smtp_reserve_hosts", "smtp_reserve_hosts", "+");
- $seen_smtp_reserve = 1;
- }
- else
- {
- $i = &skipblanks($i);
- next;
- }
- }
-
- ########### Driver configurations ##########
-
- # For aliasfile and forwardfile directors, add file, pipe, and
- # reply transports - copying from the globals if they are set.
-
- elsif ($name eq "driver")
- {
- $driver_type = $rest;
- print STDOUT "$i1$origname$i2$origrest\n";
- if ($rest eq "aliasfile" || $rest eq "forwardfile")
- {
- &add_transport("directory");
- &add_transport("directory2");
- &add_transport("file");
- &add_transport("pipe");
- &add_transport("reply") if $rest eq "forwardfile";
- }
- }
-
- # except_domains is abolished; add as negated items to domains.
-
- elsif ($name eq "except_domains" ||
- $name eq "domains")
- {
- if ($seen_domains) # If already done with these
- { # omit, and following blanks.
- $i = &skipblanks($i);
- next;
- }
- $seen_domains = 1;
-
- if (exists $o{"$prefix$driver.except_domains"})
- {
- &amalgamate("$prefix$driver.domains",
- "$prefix$driver.except_domains", "",
- "domains", "+");
- }
- else
- {
- print STDOUT "$i1$origname$i2$origrest\n";
- }
- }
-
- # except_local_parts is abolished; add as negated items to
- # local_parts.
-
- elsif ($name eq "except_local_parts" ||
- $name eq "local_parts")
- {
- if ($seen_local_parts) # If already done with these
- { # omit, and following blanks.
- $i = &skipblanks($i);
- next;
- }
- $seen_local_parts = 1;
-
- if (exists $o{"$prefix$driver.except_local_parts"})
- {
- &amalgamate("$prefix$driver.local_parts",
- "$prefix$driver.except_local_parts", "",
- "local_parts", "+");
- }
- else
- {
- print STDOUT "$i1$origname$i2$origrest\n";
- }
- }
-
- # except_senders is abolished; add as negated items to senders
-
- elsif ($name eq "except_senders" ||
- $name eq "senders")
- {
- if ($seen_senders) # If already done with these
- { # omit, and following blanks.
- $i = &skipblanks($i);
- next;
- }
- $seen_senders = 1;
-
- if (exists $o{"$prefix$driver.except_senders"})
- {
- &amalgamate("$prefix$driver.senders",
- "$prefix$driver.except_senders", "",
- "senders", "+");
- }
- else
- {
- print STDOUT "$i1$origname$i2$origrest\n";
- }
- }
-
- # This option has been renamed
-
- elsif ($name eq "directory" && $driver_type eq "aliasfile")
- {
- $origname =~ s/directory/home_directory/;
- print STDOUT "# >> Option rewritten by convert4r3\n";
- print STDOUT "$i1$origname$i2$origrest\n";
- printf STDERR "\n%03d directory renamed as " .
- "home_directory in \"$driver\" director.\n",
- ++$count;
- }
-
- # This option has been renamed
-
- elsif ($name eq "directory" && $driver_type eq "forwardfile")
- {
- $origname =~ s/directory/file_directory/;
- print STDOUT "# >> Option rewritten by convert4r3\n";
- print STDOUT "$i1$origname$i2$origrest\n";
- printf STDERR "\n%03d directory renamed as " .
- "file_directory in \"$driver\" director.\n",
- ++$count;
- }
-
- # This option has been renamed
-
- elsif ($name eq "forbid_filter_log" && $driver_type eq "forwardfile")
- {
- $origname =~ s/log/logwrite/;
- print STDOUT "# >> Option rewritten by convert4r3\n";
- print STDOUT "$i1$origname$i2$origrest\n";
- printf STDERR "\n%03d forbid_filter_log renamed as " .
- "forbid_filter_logwrite in \"$driver\" director.\n",
- ++$count;
- }
-
- # This option has been renamed
-
- elsif ($name eq "directory" && $driver_type eq "localuser")
- {
- $origname =~ s/directory/match_directory/;
- print STDOUT "# >> Option rewritten by convert4r3\n";
- print STDOUT "$i1$origname$i2$origrest\n";
- printf STDERR "\n%03d directory renamed as " .
- "match_directory in \"$driver\" director.\n",
- ++$count;
- }
-
- # mx_domains_except (and old synonym non_mx_domains) are abolished
- # (both lookuphost router and smtp transport)
-
- elsif ($name eq "mx_domains" ||
- $name eq "mx_domains_except" ||
- $name eq "non_mx_domains")
- {
- if ($seen_mx_domains) # If already done with these
- { # omit, and following blanks.
- $i = &skipblanks($i);
- next;
- }
- $seen_mx_domains = 1;
-
- if (exists $o{"$prefix$driver.mx_domains_except"} ||
- exists $o{"$prefix$driver.non_mx_domains"})
- {
- $o{"$prefix$driver.mx_domains_except"} =
- &pair("$prefix$driver.mx_domains_except",
- "$prefix$driver.non_mx_domains");
-
- &amalgamate("$prefix$driver.mx_domains",
- "$prefix$driver.mx_domains_except", "",
- "mx_domains", "+");
- }
- else
- {
- print STDOUT "$i1$origname$i2$origrest\n";
- }
- }
-
- # This option has been renamed
-
- elsif ($name eq "directory" && $driver_type eq "pipe")
- {
- $origname =~ s/directory/home_directory/;
- print STDOUT "# >> Option rewritten by convert4r3\n";
- print STDOUT "$i1$origname$i2$origrest\n";
- printf STDERR "\n%03d directory renamed as " .
- "home_directory in \"$driver\" director.\n",
- ++$count;
- }
-
- # serialize_nets is abolished
-
- elsif ($name eq "serialize_nets" ||
- $name eq "serialize_hosts")
- {
- if (!$seen_serialize)
- {
- &amalgamate("$prefix$driver.serialize_nets", "",
- "$prefix$driver.serialize_hosts", "serialize_hosts", "+");
- $seen_serialize = 1;
- }
- else
- {
- $i = &skipblanks($i);
- next;
- }
- }
-
-
- # Option not of interest; reproduce verbatim
-
- else
- {
- print STDOUT "$i1$origname$i2$origrest\n";
- }
-
-
- $last_was_blank = 0;
- }
- }
- }
-
- }
-
-# Debugging: show the associative array
-# foreach $key (sort keys %o) { print STDERR "$key = $o{$key}\n"; }
-
-print STDERR "\nEnd of configuration file conversion.\n";
-print STDERR "\n*******************************************************\n";
-print STDERR "***** Please review the generated file carefully. *****\n";
-print STDERR "*******************************************************\n\n";
-
-print STDERR "In particular:\n\n";
-
-print STDERR "(1) If you use regular expressions in any options that have\n";
-print STDERR " been rewritten by this script, they might have been put\n";
-print STDERR " inside quotes, when then were not previously quoted. This\n";
-print STDERR " means that any backslashes in them must now be escaped.\n\n";
-
-print STDERR "(2) If your configuration refers to any external files that\n";
-print STDERR " contain lists of network addresses, check that the masks\n";
-print STDERR " are specified as single numbers, e.g. /24 and NOT as dotted\n";
-print STDERR " quads (e.g. 255.255.255.0) because Exim release 3.00 does\n";
-print STDERR " not recognize the dotted quad form.\n\n";
-
-print STDERR "(3) If your configuration uses macros for lists of domains or\n";
-print STDERR " hosts or addresses, check to see if any of the references\n";
-print STDERR " have been negated. If so, you will have to rework things,\n";
-print STDERR " because the negation will apply only to the first item in\n";
-print STDERR " the macro-generated list.\n\n";
-
-print STDERR "(4) If you do not generate deliveries to pipes, files, or\n";
-print STDERR " auto-replies in your aliasfile and forwardfile directors,\n";
-print STDERR " you can remove the added transport settings.\n\n";
-
-# End of convert4r3
+++ /dev/null
-#! PERL_COMMAND
-
-# This is a Perl script that reads an Exim run-time configuration file for
-# Exim 3. It makes what changes it can for Exim 4, and also output commentary
-# on what it has done, and on things it cannot do.
-
-# It is assumed that the input is a valid Exim 3 configuration file.
-
-use warnings;
-BEGIN { pop @INC if $INC[-1] eq '.' };
-
-use Getopt::Long;
-use File::Basename;
-
-GetOptions(
- 'version' => sub {
- print basename($0) . ": $0\n",
- "build: EXIM_RELEASE_VERSIONEXIM_VARIANT_VERSION\n",
- "perl(runtime): $^V\n";
- exit 0;
- },
-);
-
-# These are lists of main options which are abolished in Exim 4.
-# The first contains options that are used to construct new options.
-
-@skipped_options = (
-"auth_hosts",
-"auth_over_tls_hosts",
-"errors_address",
-"headers_check_syntax",
-"headers_checks_fail",
-"headers_sender_verify",
-"headers_sender_verify_errmsg",
-"host_accept_relay",
-"host_auth_accept_relay",
-"host_reject_recipients",
-"local_domains",
-"local_domains_include_host",
-"local_domains_include_host_literals",
-"log_all_parents",
-"log_arguments",
-"log_incoming_port",
-"log_interface",
-"log_level",
-"log_received_sender",
-"log_received_recipients",
-"log_rewrites",
-"log_sender_on_delivery",
-"log_smtp_confirmation",
-"log_smtp_connections",
-"log_smtp_syntax_errors",
-"log_subject",
-"log_queue_run_level",
-"rbl_domains",
-"rbl_hosts",
-"rbl_reject_recipients",
-"receiver_verify",
-"receiver_verify_addresses",
-"receiver_verify_hosts",
-"receiver_verify_senders",
-"recipients_reject_except",
-"recipients_reject_except_senders",
-"relay_domains",
-"relay_domains_include_local_mx",
-"sender_address_relay",
-"sender_address_relay_hosts",
-"sender_reject_recipients",
-"sender_verify",
-"sender_verify_hosts_callback",
-"sender_verify_callback_domains",
-"sender_verify_callback_timeout",
-"sender_verify_hosts",
-"smtp_etrn_hosts",
-"smtp_expn_hosts",
-"smtp_verify",
-"tls_host_accept_relay",
-"tls_hosts",
-"tls_log_cipher",
-"tls_log_peerdn",
-"tls_verify_ciphers"
-);
-
-# The second contains options that are completely abolished and have
-# no equivalent.
-
-@abolished_options = (
-"always_bcc",
-"debug_level",
-"helo_strict_syntax",
-"kill_ip_options",
-"log_ip_options",
-"log_refused_recipients",
-"message_size_limit_count_recipients",
-"rbl_log_headers",
-"rbl_log_rcpt_count",
-"receiver_try_verify",
-"refuse_ip_options",
-"relay_match_host_or_sender",
-"sender_try_verify",
-"sender_verify_batch",
-"sender_verify_fixup",
-"sender_verify_reject",
-"sender_verify_max_retry_rate",
-);
-
-# This is a list of options that are not otherwise handled, but which
-# contain domain or host lists that have to be processed so that any
-# regular expressions are marked "not for expansion".
-
-@list_options = (
-"dns_again_means_nonexist",
-"hold_domains",
-"hosts_treat_as_local",
-"percent_hack_domains",
-"queue_smtp_domains",
-"helo_accept_junk_hosts",
-"host_lookup",
-"ignore_fromline_hosts",
-"rfc1413_hosts",
-"sender_unqualified_hosts",
-"smtp_reserve_hosts",
-"tls_advertise_hosts",
-"tls_verify_hosts",
-);
-
-
-
-##################################################
-# Output problem rubric once #
-##################################################
-
-sub rubric {
-return if $rubric_output;
-$rubric_output = 1;
-print STDERR "\n" .
-"** The following comments describe problems that have been encountered\n" .
-" while converting an Exim 3 runtime file for Exim 4. More detail can\n" .
-" be found in the file doc/Exim4.upgrade.\n";
-}
-
-
-##################################################
-# Analyse one line #
-##################################################
-
-sub checkline{
-my($line) = $_[0];
-
-return "comment" if $line =~ /^\s*(#|$)/;
-return "end" if $line =~ /^\s*end\s*$/i;
-
-# Macros are recognized only in the first section of the file.
-
-return "macro" if $prefix eq "" && $line =~ /^\s*[A-Z]/;
-
-# In retry and rewrite sections, the type is always "other"
-
-return "other" if $prefix eq "=retry" || $prefix eq "=rewrite";
-
-# Pick out the name at the start and the rest of the line (into global
-# variables) and return whether the start of a driver or not.
-
-($hide,$name,$rest) = $line =~ /^\s*(hide\s+|)([a-z0-9_]+)\s*(.*?)\s*$/;
-
-# If $rest begins with a colon, this is a driver name
-
-return "driver" if $rest =~ /^:/;
-
-# If $rest begins with an = the value of the option is given explicitly;
-# remove the = from the start. Turn "yes"/"no" into "true"/"false".
-
-if ($rest =~ /^=/)
- {
- $rest =~ s/^=\s*//;
- $rest = "true" if $rest eq "yes";
- $rest = "false" if $rest eq "no";
- }
-
-# Otherwise we have a boolean option. Set up a "true"/"false" value.
-
-else
- {
- if ($name =~ /^not?_/) # Recognize "no_" or "not_"
- {
- $rest = "false";
- $name =~ s/^not?_//;
- }
- else
- {
- $rest = "true";
- }
- }
-
-return "option";
-}
-
-
-
-##################################################
-# Negate a list of things #
-##################################################
-
-# Can be tricky, because there may be comment lines in the list.
-# Also, lists may have different delimiters.
-
-sub negate {
-my($list) = $_[0];
-my($delim) = ":";
-my($leadin) = "";
-
-return $list if ! defined $list;
-
-($list) = $list =~ /^"?(.*?)"?\s*$/s; # Remove surrounding quotes
-$list =~ s/\\\s*\n\s*//g; # Remove continuation markers
-
-if ($list =~ /^(\s*<(\S)\s*)(.*)/s)
- {
- $leadin = $1;
- $delim = $2;
- $list = $3;
- }
-
-$list =~ s/^\s+//;
-$list =~ s/\Q$delim$delim/>%%%%</g;
-@split = split /\s*\Q$delim\E\s*/s, $list;
-
-foreach $item (@split)
- {
- $item =~ s/>%%%%</$delim$delim/g;
-
- if ($item =~ /^\s*#/)
- {
- $item =~ s/((?:^\s*#[^\n]*\n)+\s*)/$1! /mg;
- $item =~ s/!\s*!//sg;
- }
- else
- {
- if ($item =~ /^\s*!(.*)/)
- { $item = $1; }
- else
- { $item = "! " . $item; }
- }
- }
-
-$" = " $delim \\\n ";
-$leadin .= " " if $leadin !~ /(^|\s)$/;
-return "$leadin@split";
-}
-
-
-
-##################################################
-# Prevent regex expansion in a list of things #
-##################################################
-
-# Can be tricky, because there may be comment lines in the list.
-# Also, lists may have different delimiters.
-
-sub no_expand_regex {
-my($list) = $_[0];
-my($delim) = ":";
-my($leadin) = "";
-
-return $list if ! defined $list;
-
-$delim = $_[1] if (defined $_[1]);
-
-my($is_route_list) = $delim eq ";";
-
-($list) = $list =~ /^"?(.*?)"?\s*$/s; # Remove surrounding quotes
-$list =~ s/\\\s*\n\s*//g; # Remove continuation markers
-
-if ($list =~ /^(\s*<(\S)\s*)(.*)/s)
- {
- $leadin = $1;
- $delim = $2;
- $list = $3;
- }
-
-$list =~ s/^\s+//;
-$list =~ s/\Q$delim$delim/>%%%%</g;
-@split = split /\s*\Q$delim\E\s*/s, $list;
-
-my($changed) = 0;
-foreach $item (@split)
- {
- $item =~ s/>%%%%</$delim$delim/g;
- if ($item =~ /^\^/)
- {
- # Fudge for route_list items
-
- if ($is_route_list)
- {
- $item = "\\N$item"; # Only one item ...
- }
- else
- {
- $item = "\\N$item\\N";
- }
- $changed = 1;
- }
- }
-print STDOUT
- "#!!# Regular expressions enclosed in \\N...\\N to avoid expansion\n"
- if $changed;
-
-$" = " $delim \\\n ";
-$leadin .= " " if $leadin !~ /(^|\s)$/;
-return "$leadin@split";
-}
-
-
-
-##################################################
-# Sort out lookups in an address list #
-##################################################
-
-# Can be tricky, because there may be comment lines in the list.
-# Also, lists may have different delimiters.
-
-sub sort_address_list {
-my($list) = $_[0];
-my($name) = $_[1];
-my($delim) = ":";
-my($leadin) = "";
-my($quoted) = 0;
-
-return $list if ! defined $list;
-
-if ($list =~ /^"(.*?)"\s*$/s) # Remove surrounding quotes
- {
- $list = $1;
- $quoted = 1;
- }
-
-$list =~ s/\\\s*\n\s*//g; # Remove continuation markers
-
-if ($list =~ /^(\s*<(\S)\s*)(.*)/s)
- {
- $leadin = $1;
- $delim = $2;
- $list = $3;
- }
-
-$list =~ s/^\s+//;
-$list =~ s/\Q$delim$delim/>%%%%</g;
-@split = split /\s*\Q$delim\E\s*/s, $list;
-
-foreach $item (@split)
- {
- $item =~ s/>%%%%</$delim$delim/g;
- if ($item =~ /^\s*(?:partial-)?(\w+;.*)$/)
- {
- my($lookup) = $1;
- if ($lookup =~ /^lsearch|^dbm|^cdb|^nis[^p]/)
- {
- &rubric();
- print STDERR "\n" .
-"** The Exim 3 \"$name\" option specifies an address\n" .
-" list that includes the item\n\n" .
-" $item\n\n" .
-" In Exim 4 address lists, single-key lookups without a local part just\n" .
-" look up the complete address. They don't also try the domain, as\n" .
-" happened in Exim 3. The item has been rewritten as two items to make\n" .
-" it behave in the same way as Exim 3, but you should check to see if\n" .
-" this is actually what you want.\n";
-
- $item = "*\@$item $delim $lookup";
- }
- }
- }
-
-$" = " $delim \\\n ";
-$leadin .= " " if $leadin !~ /(^|\s)$/;
-
-return $quoted? "\"$leadin@split\"" : "$leadin@split";
-}
-
-
-
-##################################################
-# Quote a string against expansion #
-##################################################
-
-# Used for setting up new "domains" options
-
-sub expquote {
-my($s) = $_[0];
-$s =~ s/\$/\\\$/sg;
-$s =~ s/\\(?!\s*\n)/\\\\/sg;
-return $s;
-}
-
-
-
-##################################################
-# Dequote an option string #
-##################################################
-
-# If the original list is not quoted, do nothing.
-# If it is quoted, just get rid of the quotes.
-
-sub unquote {
-my($s) = $_[0];
-$s =~ s/^"(.*)"$/$1/s;
-return $s;
-}
-
-
-##################################################
-# Quote/dequote an option string #
-##################################################
-
-# If the original list is not quoted, quote it against expansion.
-# If it is quoted, just get rid of the quotes. Also, indent any
-# continuations.
-
-sub acl_quote {
-my($s) = $_[0];
-$s = ($s =~ /^"(.*)"$/s)? $1 : &expquote($s);
-$s =~ s/\n/\n /g;
-$s =~ s/\n\s{11,}/\n /g;
-return $s;
-}
-
-
-##################################################
-# Handle abolished driver options #
-##################################################
-
-sub abolished {
-my($hash) = shift @_;
-my($name) = shift @_;
-for $abolished (@_)
- {
- if (defined $$hash{$abolished})
- {
- &rubric();
- print STDERR "\n" .
-"** $name used the \"$abolished\" option, which no\n".
-" longer exists. The option has been removed.\n";
- print STDOUT "#!!# $abolished option removed\n";
- delete $$hash{$abolished};
- }
- }
-}
-
-
-
-##################################################
-# Handle renamed driver options #
-##################################################
-
-sub renamed {
-my($hash,$old,$new) = @_;
-if (defined $$hash{$old})
- {
- print STDOUT "#!!# $old renamed $new\n";
- $$hash{$new} = $$hash{$old};
- delete $$hash{$old};
- }
-}
-
-
-
-##################################################
-# Comment on user names in require_files #
-##################################################
-
-sub check_require {
-my($string, $name) = @_;
-
-$string =~ s/::/[[[]]]/g;
-my(@list) = split /:/, $string;
-my($item);
-
-for $item (@list)
- {
- if ($item =~ /^\s*[\w,]+\s*$/)
- {
- &rubric();
- $item =~ s/^\s*//;
- $item =~ s/\s*$//;
- print STDERR "\n" .
-"** A setting of require_files in the $name contains\n" .
-" what appears to be a user name ('$item'). The ability to check files\n" .
-" as a specific user is done differently in Exim 4. In fact, because the\n" .
-" routers run as root, you may not need this at all.\n"
- }
- }
-}
-
-
-##################################################
-# Handle current and home directory #
-##################################################
-
-sub handle_current_and_home_directory {
-my($hash,$driver,$name) = @_;
-
-for ("current_directory", "home_directory")
- {
- if (defined $$hash{$_} && $$hash{$_} eq "check_local_user")
- {
- my($article) = (substr($driver, 0, 1) eq "a")? "an" : "a";
- &rubric();
- print STDERR "\n" .
-"** The Exim 3 configuration contains $article '$driver' director called\n" .
-" '$name', which set '$_' to the special value\n" .
-" 'check_local_user'. This facility has been abolished in Exim 4 because\n" .
-" it is no longer necessary. The setting has therefore been omitted. See\n" .
-" note X.\n";
- delete $$hash{$_};
- }
- else
- {
- &renamed($hash, $_, "transport_$_");
- }
- }
-}
-
-
-
-##################################################
-# Handle batch/bsmtp for appendfile/pipe #
-##################################################
-
-sub handle_batch_and_bsmtp{
-my($hash) = @_;
-
-if (defined $$hash{"bsmtp"})
- {
- if ($$hash{"bsmtp"} ne "none")
- {
- $$hash{"use_bsmtp"} = "true";
- $$hash{"message_prefix"} = "\"HELO \$primary_host_name\\n\""
- if defined $$hash{"bsmtp_helo"} && $$hash{"bsmtp_helo"} eq "true";
- }
-
- if ($$hash{"bsmtp"} eq "one")
- {
- delete $$hash{"batch"};
- }
- else
- {
- $$hash{"batch"} = $$hash{"bsmtp"};
- }
-
- delete $$hash{"bsmtp"};
- delete $$hash{"bsmtp_helo"};
- }
-
-if (defined $$hash{"batch"} && $$hash{"batch"} ne "none")
- {
- $$hash{"batch_max"} = "100" if !defined $$hash{"batch_max"};
- $$hash{"batch_id"} = "\$domain" if $$hash{"batch"} eq "domain";
- }
-else
- {
- $$hash{"batch_max"} = "1" if defined $$hash{"batch_max"};
- }
-delete $$hash{"batch"};
-}
-
-
-
-##################################################
-# Output one option #
-##################################################
-
-sub outopt {
-my($hash, $key, $no_expand) = @_;
-my($data) = $$hash{$key};
-
-print STDOUT "hide " if defined $$hash{"$key-hide"};
-
-# Output booleans in the form that doesn't use "="
-
-if ($data eq "true")
- {
- print STDOUT "$key\n";
- }
-elsif ($data eq "false")
- {
- print STDOUT "no_$key\n";
- }
-else
- {
- if ($no_expand)
- {
- printf STDOUT ("$key = %s\n", &no_expand_regex($data));
- }
- else
- {
- print STDOUT "$key = $data\n";
- }
- }
-}
-
-
-
-##################################################
-# Output the options for one driver #
-##################################################
-
-# Put the "driver" option first
-
-sub outdriver {
-my($hash) = $_[0];
-print STDOUT " driver = $$hash{'driver'}\n";
-foreach $key (sort keys %$hash)
- {
- next if $key eq "driver" || $key =~ /-hide$/;
- print STDOUT " ";
- &outopt($hash, $key, 0);
- }
-}
-
-
-
-##################################################
-# Output a rewrite or a retry line #
-##################################################
-
-# These lines start with patterns which are now always expanded. If the
-# pattern is a regex, arrange for it not to expand.
-
-sub print_no_expand {
-my($s) = $_[0];
-if ($s =~ /^\^/)
- {
- if (!$escape_output)
- {
- &rubric();
- print STDERR "\n" .
-"** You have a retry or rewrite pattern that is a regular expression. Because\n" .
-" these patterns are now always expanded, you need to be sure that the\n" .
-" special characters in the regex are not interpreted by the expander.\n" .
-" \\N has been inserted at the start of the regex to prevent the rest of\n" .
-" it from being expanded.\n";
- $escape_output = 1;
- }
- print STDOUT "\\N";
- }
-print STDOUT "$s\n";
-}
-
-
-
-##################################################
-# Test a boolean main option #
-##################################################
-
-# This just saves a lot of typing
-
-sub bool {
-return defined $main{$_[0]} && $main{$_[0]} eq "true";
-}
-
-
-
-##################################################
-# Main program #
-##################################################
-
-print STDERR "Runtime configuration file converter for Exim release 4.\n";
-
-$transport_start = $director_start = $router_start = $retry_start
- = $rewrite_start = $auth_start = 999999;
-
-$macro_output = "";
-$rubric_output = 0;
-$errmsg_output = 0;
-$key_output = 0;
-$unk_output = 0;
-$escape_output = 0;
-$add_no_more = 0;
-$add_caseful_local_part = 0;
-$done_dns_check_names = 0;
-
-$queue_only_load_was_present = 0;
-$deliver_queue_load_max_was_present = 0;
-
-# Read the entire file into an array
-
-chomp(@c = <STDIN>);
-$clen = scalar @c;
-
-# Remove the standard comment that appears at the end of the default
-
-if ($clen > 0 && $c[$clen-1] =~ /^#\s*End of Exim configuration file\s*/i)
- {
- pop @c;
- $clen--;
- }
-
-# The first pass over the input fishes out all the options settings in the
-# main, transport, director, and router sections, and places their values in
-# associative arrays. It also notes the starting position of all the sections.
-
-$prefix = "";
-%main = ();
-$hash = \%main;
-
-for ($i = 0; $i < $clen; $i++)
- {
- # Change references to +allow_unknown and +warn_unknown into +include_unknown
-
- if ($c[$i] =~ /\+(?:allow|warn)_unknown/)
- {
- if (!$unk_output)
- {
- &rubric();
- print STDERR "\n" .
-"** You have used '+allow_unknown' or '+warn_unknown' in a configuration\n" .
-" option. This has been converted to '+include_unknown', but the action\n" .
-" is different in Exim 4, so you should review all the relevant options.\n";
- $unk_output = 1;
- }
- $c[$i] =~ s/\+(?:allow|warn)_unknown/+include_unknown/g;
- }
-
- # Any reference to $errmsg_recipient is changed to $bounce_recipient
-
- if ($c[$i] =~ /\$errmsg_recipient/)
- {
- if (!$errmsg_output)
- {
- &rubric();
- print STDERR "\n" .
-"** References to \$errmsg_recipient have been changed to \$bounce_recipient\n";
- $errmsg_output = 1;
- }
- $c[$i] =~ s/\$errmsg_recipient/\$bounce_recipient/g;
- }
-
-
- # Analyse the type of line
-
- $type = &checkline($c[$i]);
- next if $type eq "comment";
-
- # Output a warning if $key is used
-
- if ($c[$i] =~ /\$key/ && !$key_output)
- {
- &rubric();
- print STDERR "\n" .
-"** You have used '\$key' in a configuration option. This variable does not\n" .
-" exist in Exim 4. Instead, the value you need for your lookup will be\n" .
-" in one of the other variables such as '\$domain' or '\$host'. You will\n" .
-" need to edit the new configuration to sort this out.\n";
- $key_output = 1;
- }
-
- # Save macro definitions so we can output them first; must handle
- # continuations.
-
- if ($type eq "macro")
- {
- $macro_output .= "$c[$i++]\n" while $c[$i] =~ /\\\s*$|^\s*#/;
- $macro_output .= "$c[$i]\n";
- }
-
- # Handle end of section
-
- elsif ($type eq "end")
- {
- if ($prefix eq "=rewrite")
- {
- $prefix = "a.";
- $auth_start = $i + 1;
- last;
- }
- elsif ($prefix eq "=retry")
- {
- $prefix = "=rewrite";
- $rewrite_start = $i + 1;
- }
- elsif ($prefix eq "r.")
- {
- $prefix = "=retry";
- $retry_start = $i + 1;
- }
- elsif ($prefix eq "d.")
- {
- $prefix = "r.";
- $router_start = $i + 1;
- }
- elsif ($prefix eq "t.")
- {
- $prefix = "d.";
- $director_start = $i + 1;
- }
- elsif ($prefix eq "")
- {
- $prefix = "t.";
- $transport_start = $i + 1;
- }
- }
-
- # Handle start of a new director, router or transport driver
-
- elsif ($type eq "driver" && $prefix !~ /^=/)
- {
- $hash = {};
- if (defined $driverlist{"$prefix$name"})
- {
- die "*** There are two drivers with the name \"$name\"\n";
- }
- $driverlist{"$prefix$name"} = $hash;
- $first_director = $name if !defined $first_director && $prefix eq "d.";
- }
-
- # Handle definition of an option; we must pull in any continuation
- # strings, and save the value in the current hash. Note if the option
- # is hidden.
-
- elsif ($type eq "option")
- {
- my($nextline) = "";
-
- while ($i < $clen - 1 && ($rest =~ /\\\s*$/s || $nextline =~ /^\s*#/))
- {
- $nextline = $c[++$i];
- $rest .= "\n$nextline";
- }
-
- $$hash{$name} = $rest;
- $$hash{"$name-hide"} = 1 if $hide ne "";
- }
- }
-
-
-# Generate the new configuration. Start with a warning rubric.
-
-print STDOUT "#!!# This file is output from the convert4r4 script, which tries\n";
-print STDOUT "#!!# to convert Exim 3 configurations into Exim 4 configurations.\n";
-print STDOUT "#!!# However, it is not perfect, especially with non-simple\n";
-print STDOUT "#!!# configurations. You must check it before running it.\n";
-print STDOUT "\n\n";
-
-# Output the macro definitions
-
-if ($macro_output ne "")
- {
- print STDOUT "#!!# All macro definitions have been gathered here to ensure\n";
- print STDOUT "#!!# they precede any references to them.\n\n";
- print STDOUT "$macro_output\n";
- }
-
-# Output some default pointers to ACLs for RCPT and DATA time. If no Exim 3
-# options that apply are set, non-restricting ACLs are generated.
-
-print STDOUT "#!!# These options specify the Access Control Lists (ACLs) that\n";
-print STDOUT "#!!# are used for incoming SMTP messages - after the RCPT and DATA\n";
-print STDOUT "#!!# commands, respectively.\n\n";
-
-print STDOUT "acl_smtp_rcpt = check_recipient\n";
-print STDOUT "acl_smtp_data = check_message\n\n";
-
-if (defined $main{"auth_over_tls_hosts"})
- {
- print STDOUT "#!!# This option specifies the Access Control List (ACL) that\n";
- print STDOUT "#!!# is used after an AUTH command.\n\n";
- print STDOUT "acl_smtp_auth = check_auth\n\n";
- }
-
-if (&bool("smtp_verify") ||
- defined $main{"smtp_etrn_hosts"} ||
- defined $main{"smtp_expn_hosts"})
- {
- print STDOUT "#!!# These options specify the Access Control Lists (ACLs) that\n";
- print STDOUT "#!!# are used to control the ETRN, EXPN, and VRFY commands.\n";
- print STDOUT "#!!# Where no ACL is defined, the command is locked out.\n\n";
-
- print STDOUT "acl_smtp_etrn = check_etrn\n" if defined $main{"smtp_etrn_hosts"};
- print STDOUT "acl_smtp_expn = check_expn\n" if defined $main{"smtp_expn_hosts"};
- print STDOUT "acl_smtp_vrfy = check_vrfy\n" if &bool("smtp_verify");
- print STDOUT "\n";
- }
-
-# If local_domains was set, get its value; otherwise set to "@". Add into it
-# appropriate magic for local_domains_include_host[_literals].
-
-$local_domains = (defined $main{"local_domains"})? $main{"local_domains"} : "@";
-
-$ldsep = ":";
-if ($local_domains =~ /^\s*<(.)\s*(.*)/s)
- {
- $ldsep = $1;
- $local_domains = $2;
- }
-
-$local_domains = "\@[] $ldsep " . $local_domains
- if defined $main{"local_domains_include_host_literals"} &&
- $main{"local_domains_include_host_literals"} eq "true";
-
-$local_domains = "\@ $ldsep " . $local_domains
- if defined $main{"local_domains_include_host"} &&
- $main{"local_domains_include_host"} eq "true";
-
-$local_domains = "<$ldsep " . $local_domains if $ldsep ne ":";
-
-# Output a domain list setting for these domains, provided something is defined
-
-if ($local_domains !~ /^\s*$/)
- {
- print STDOUT "#!!# This setting defines a named domain list called\n";
- print STDOUT "#!!# local_domains, created from the old options that\n";
- print STDOUT "#!!# referred to local domains. It will be referenced\n";
- print STDOUT "#!!# later on by the syntax \"+local_domains\".\n";
- print STDOUT "#!!# Other domain and host lists may follow.\n\n";
-
- printf STDOUT ("domainlist local_domains = %s\n\n",
- &no_expand_regex($local_domains));
- }
-
-$relay_domains = (defined $main{"relay_domains"})? $main{"relay_domains"} : "";
-
-$ldsep = ":";
-if ($relay_domains =~ /^\s*<(.)\s*(.*)/s)
- {
- $ldsep = $1;
- }
-
-if (defined $main{"relay_domains_include_local_mx"})
- {
- $relay_domains .= ($relay_domains =~ /^\s*$/)? "\@mx_any" :
- " $ldsep \@mx_any";
- }
-
-printf STDOUT ("domainlist relay_domains = %s\n",
- &no_expand_regex($relay_domains))
- if $relay_domains !~ /^\s*$/;
-
-
-# If ignore_errmsg_errors is set, we are going to force 0s as the value
-# for ignore_errmsg_errors_after, so arrange to skip any other value.
-
-push @skipped_options, "ignore_errmsg_errors_after"
- if &bool("ignore_errmsg_errors");
-
-
-# If rbl_domains is set, split it up and generate six lists:
-# rbl_warn_domains, rbl_warn_domains_skiprelay
-# rbl_reject_domains, rbl_reject_domains_skiprelay
-# rbl_accept_domains, rbl_accept_domains_skiprelay
-
-if (defined $main{"rbl_domains"})
- {
- my($s) = &unquote($main{"rbl_domains"});
- $s =~ s/\s*\\\s*\n\s*/ /g;
- my(@list) = split /\s*:\s*/, $s;
-
- foreach $d (@list)
- {
- my(@sublist) = split /\//, $d;
- my($name) = shift @sublist;
- my($warn) = 0;
- if (defined $main{"rbl_reject_recipients"})
- {
- $warn = $main{"rbl_reject_recipients"} ne "true";
- }
-
- foreach $o (@sublist)
- {
- $warn = 1 if $o eq "warn";
- $warn = 0 if $o eq "reject";
- $warn = 2 if $o eq "accept";
- $skiprelay = 1 if $o eq "skiprelay";
- }
-
- if ($skiprelay)
- {
- if ($warn == 0)
- {
- $rbl_reject_skiprelay .= ((defined $rbl_reject_skiprelay)? ":":"").$name;
- }
- elsif ($warn == 1)
- {
- $rbl_warn_skiprelay .= ((defined $rbl_warn_skiprelay)? ":":"").$name;
- }
- elsif ($warn == 2)
- {
- $rbl_accept_skiprelay .= ((defined $rbl_accept_skiprelay)? ":":"").$name;
- }
- }
- else
- {
- if ($warn == 0)
- {
- $rbl_reject_domains .= ((defined $rbl_reject_domains)? ":":"").$name;
- }
- elsif ($warn == 1)
- {
- $rbl_warn_domains .= ((defined $rbl_warn_domains)? ":":"").$name;
- }
- elsif ($warn == 2)
- {
- $rbl_accept_domains .= ((defined $rbl_accept_domains)? ":":"").$name;
- }
- }
- }
- }
-
-
-# Output host list settings
-
-printf STDOUT ("hostlist auth_hosts = %s\n",
- &no_expand_regex($main{"auth_hosts"}))
- if defined $main{"auth_hosts"};
-printf STDOUT ("hostlist rbl_hosts = %s\n",
- &no_expand_regex($main{"rbl_hosts"}))
- if defined $main{"rbl_hosts"};
-printf STDOUT ("hostlist relay_hosts = %s\n",
- &no_expand_regex($main{"host_accept_relay"}))
- if defined $main{"host_accept_relay"};
-printf STDOUT ("hostlist auth_relay_hosts = %s\n",
- &no_expand_regex($main{"host_auth_accept_relay"}))
- if defined $main{"host_auth_accept_relay"};
-
-printf STDOUT ("hostlist auth_over_tls_hosts = %s\n",
- &no_expand_regex($main{"auth_over_tls_hosts"}))
- if defined $main{"auth_over_tls_hosts"};
-printf STDOUT ("hostlist tls_hosts = %s\n",
- &no_expand_regex($main{"tls_hosts"}))
- if defined $main{"tls_hosts"};
-printf STDOUT ("hostlist tls_relay_hosts = %s\n",
- &no_expand_regex($main{"tls_host_accept_relay"}))
- if defined $main{"tls_host_accept_relay"};
-
-print STDOUT "\n";
-
-
-# Convert various logging options
-
-$log_selector = "";
-$sep = " \\\n ";
-
-if (defined $main{"log_level"})
- {
- my($level) = $main{"log_level"};
- $log_selector .= "$sep -retry_defer$sep -skip_delivery" if $level < 5;
- $log_selector .= "$sep -lost_incoming_connection$sep -smtp_syntax_error" .
- "$sep -delay_delivery" if $level < 4;
- $log_selector .= "$sep -size_reject" if $level < 2;
- }
-
-$log_selector .= "$sep -queue_run"
- if defined $main{"log_queue_run_level"} &&
- defined $main{"log_level"} &&
- $main{"log_queue_run_level"} > $main{"log_level"};
-
-$log_selector .= "$sep +address_rewrite" if &bool("log_rewrites");
-$log_selector .= "$sep +all_parents" if &bool("log_all_parents");
-$log_selector .= "$sep +arguments" if &bool("log_arguments");
-$log_selector .= "$sep +incoming_port" if &bool("log_incoming_port");
-$log_selector .= "$sep +incoming_interface" if &bool("log_interface");
-$log_selector .= "$sep +received_sender" if &bool("log_received_sender");
-$log_selector .= "$sep +received_recipients" if &bool("log_received_recipients");
-$log_selector .= "$sep +sender_on_delivery" if &bool("log_sender_on_delivery");
-$log_selector .= "$sep +smtp_confirmation" if &bool("log_smtp_confirmation");
-$log_selector .= "$sep +smtp_connection" if &bool("log_smtp_connections");
-$log_selector .= "$sep +smtp_syntax_error" if &bool("log_smtp_syntax_errors");
-$log_selector .= "$sep +subject" if &bool("log_subject");
-$log_selector .= "$sep +tls_cipher" if &bool("tls_log_cipher");
-$log_selector .= "$sep +tls_peerdn" if &bool("tls_log_peerdn");
-
-
-if ($log_selector ne "")
- {
- print STDOUT "#!!# All previous logging options are combined into a single\n"
- . "#!!# option in Exim 4. This setting is an approximation to\n"
- . "#!!# the previous state - some logging has changed.\n\n";
- print STDOUT "log_selector = $log_selector\n\n";
- }
-
-# If deliver_load_max is set, replace it with queue_only_load (taking the
-# lower value if both set) and also set deliver_queue_load_max if it is
-# not already set. When scanning for output, deliver_load_max is skipped.
-
-if (defined $main{"deliver_load_max"})
- {
- &rubric();
- print STDERR "\n" .
-"** deliver_load_max is abolished in Exim 4.\n";
-
- if (defined $main{"queue_only_load"})
- {
- $queue_only_load_was_present = 1;
- if ($main{"queue_only_load"} < $main{"deliver_load_max"})
- {
- print STDERR
-" As queue_only_load was set lower, deliver_load_max is just removed.\n";
- }
- else
- {
- print STDERR
-" As queue_only_load was set higher, it's value has been replaced by\n" .
-" the value of deliver_load_max.\n";
- $main{"queue_only_load"} = $main{"deliver_load_max"};
- }
- }
- else
- {
- print STDERR
-" queue_only_load has been set to the load value.\n";
- $main{"queue_only_load"} = $main{"deliver_load_max"};
- }
-
- if (!defined $main{"deliver_queue_load_max"})
- {
- print STDERR
-" deliver_queue_load_max has been set to the value of queue_only_load.\n";
- $main{"deliver_queue_load_max"} = $main{"queue_only_load"};
- }
- else
- {
- $deliver_queue_load_max_was_present = 1;
- }
- }
-
-
-# Now we scan through the various parts of the file again, making changes
-# as necessary.
-
-# -------- The main configuration --------
-
-$prefix = "";
-MainLine: for ($i = 0; $i < $clen; $i++)
- {
- my($nextline) = "";
- $type = &checkline($c[$i]);
- last if $type eq "end";
-
- if ($type eq "macro")
- {
- $i++ while $c[$i] =~ /\\\s*$|^\s*#/;
- next;
- }
-
- if ($type eq "comment") { print STDOUT "$c[$i]\n"; next; }
-
- # Collect any continuation lines for an option setting
-
- while ($rest =~ /\\\s*$/s || $nextline =~ /^\s*#/)
- {
- $nextline = $c[++$i];
- $rest .= "\n$nextline";
- }
-
- $rest =~ s/^=\s*//;
-
- # Deal with main options that are skipped (they are used in other
- # options in other places).
-
- for $skipped (@skipped_options)
- {
- next MainLine if $name eq $skipped;
- }
-
- # Deal with main options that are totally abolished
-
- for $abolished (@abolished_options)
- {
- if ($name eq $abolished)
- {
- &rubric();
- print STDERR "\n" .
-"** The $name option no longer exists, and has no equivalent\n" .
-" in Exim 4.\n";
- next MainLine;
- }
- }
-
- # There is a special case for rbl_warn_header
-
- if ($name eq "rbl_warn_header")
- {
- &rubric();
- print STDERR "\n" .
-"** The $name option no longer exists. In Exim 4 you can achieve the\n" .
-" effect by adding a suitable \"message\" statement in the ACL.\n";
- }
-
- # There is a special case for sender_reject and host_reject
-
- elsif ($name eq "sender_reject" || $name eq "host_reject")
- {
- &rubric();
- print STDERR "\n" .
-"** The $name option no longer exists. Its data has been used in\n" .
-" an Access Control List as if it were in ${name}_recipients.\n";
- }
-
- # And a special message for prohibition_message
-
- elsif ($name eq "prohibition_message")
- {
- &rubric();
- print STDERR "\n" .
-"** The prohibition_message option no longer exists. The facility is\n" .
-" provided in a different way in Exim 4, via the \"message\" keyword\n" .
-" in Access Control Lists. It isn't possible to do an automatic conversion,\n" .
-" so the value of prohibition_message has been ignored. You will have to\n" .
-" modify the ACLs if you want to reinstate the feature.\n";
- }
-
- # auth_always_advertise gets converted to auth_advertise_hosts
-
- elsif ($name eq "auth_always_advertise")
- {
- print STDOUT "#!!# auth_always_advertise converted to auth_advertise_hosts\n";
- if (&bool("auth_always_advertise"))
- {
- print STDOUT "auth_advertise_hosts = *\n";
- }
- else
- {
- $sep = "";
- print STDOUT "auth_advertise_hosts =";
- if (defined $main{"auth_hosts"})
- {
- print STDOUT "$sep +auth_hosts";
- $sep = " :";
- }
- if (defined $main{"host_accept_relay"})
- {
- print STDOUT "$sep !+relay_hosts";
- $sep = " :";
- }
- if (defined $main{"host_auth_accept_relay"})
- {
- print STDOUT "$sep +auth_relay_hosts";
- }
- print STDOUT "\n";
- }
- }
-
- # Deal with main options that have to be rewritten
-
- elsif ($name eq "accept_timeout")
- {
- print STDOUT "#!!# accept_timeout renamed receive_timeout\n";
- print STDOUT "receive_timeout = $rest\n";
- }
-
- elsif ($name eq "collapse_source_routes")
- {
- print STDOUT "#!!# collapse_source_routes removed\n";
- print STDOUT "#!!# It has been a no-op since 3.10.\n";
- }
-
- elsif ($name eq "daemon_smtp_service")
- {
- print STDOUT "#!!# daemon_smtp_service renamed daemon_smtp_port\n";
- print STDOUT "daemon_smtp_port = $rest\n";
- }
-
- elsif ($name eq "dns_check_names" || $name eq "dns_check_names_pattern")
- {
- if (!$done_dns_check_names)
- {
- if (&bool("dns_check_names"))
- {
- if (defined $main{"dns_check_names_pattern"})
- {
- &outopt(\%main, "dns_check_names_pattern", 0);
- }
- }
-
- else
- {
- print STDOUT "#!!# dns_check_names has been abolished\n";
- print STDOUT "#!!# setting dns_check_pattern empty to turn off check\n";
- print STDOUT "dns_check_names_pattern =\n";
- }
-
- $done_dns_check_names = 1;
- }
- }
-
- elsif ($name eq "deliver_load_max")
- {
- print STDOUT "deliver_queue_load_max = $main{'deliver_queue_load_max'}\n"
- if !$deliver_queue_load_max_was_present;
- print STDOUT "queue_only_load = $main{'queue_only_load'}\n"
- if !$queue_only_load_was_present;
- }
-
- elsif ($name eq "errmsg_file")
- {
- print STDOUT "#!!# errmsg_file renamed bounce_message_file\n";
- print STDOUT "bounce_message_file = $rest\n";
- }
-
- elsif ($name eq "errmsg_text")
- {
- print STDOUT "#!!# errmsg_text renamed bounce_message_text\n";
- print STDOUT "bounce_message_text = $rest\n";
- }
-
- elsif ($name eq "forbid_domain_literals")
- {
- print STDOUT "#!!# forbid_domain_literals replaced by allow_domain_literals\n";
- print STDOUT "allow_domain_literals = ",
- &bool("forbid_domain_literals")? "false" : "true", "\n";
- }
-
- elsif ($name eq "freeze_tell_mailmaster")
- {
- print STDOUT "#!!# freeze_tell_mailmaster replaced by freeze_tell\n";
- if (&bool("freeze_tell_mailmaster"))
- {
- print STDOUT "freeze_tell = ",
- ((defined $main{"errors_address"})?
- $main{"errors_address"} : "postmaster"), "\n";
- }
- else
- {
- print STDOUT "#!!# freeze_tell is unset by default\n";
- }
- }
-
- elsif ($name eq "helo_verify")
- {
- print STDOUT "#!!# helo_verify renamed helo_verify_hosts\n";
- printf STDOUT ("helo_verify_hosts = %s\n", &no_expand_regex($rest));
- }
-
- elsif ($name eq "ignore_errmsg_errors")
- {
- print STDOUT "ignore_bounce_errors_after = 0s\n";
- }
-
- elsif ($name eq "ignore_errmsg_errors_after")
- {
- print STDOUT "#!!# ignore_errmsg_errors_after renamed ignore_bounce_errors_after\n";
- print STDOUT "ignore_bounce_errors_after = $rest\n";
- }
-
- elsif ($name eq "ipv4_address_lookup" || $name eq "dns_ipv4_lookup")
- {
- print STDOUT "#!!# $name changed to dns_ipv4_lookup\n"
- if $name eq "ipv4_address_lookup";
- print STDOUT "#!!# dns_ipv4_lookup is now a domain list\n";
- if (&bool($name))
- {
- print STDOUT "dns_ipv4_lookup = *\n";
- }
- else
- {
- print STDOUT "#!!# default for dns_ipv4_lookup is unset\n";
- }
- }
-
- elsif ($name eq "locally_caseless")
- {
- print STDOUT "#!!# locally_caseless removed\n";
- print STDOUT "#!!# caseful_local_part will be added to ex-directors\n";
- $add_caseful_local_part = 1;
- }
-
- elsif ($name eq "message_filter_directory2_transport")
- {
- print STDOUT "#!!# message_filter_directory2_transport removed\n";
- }
-
- elsif ($name =~ /^message_filter(.*)/)
- {
- print STDOUT "#!!# $name renamed system_filter$1\n";
- print STDOUT "system_filter$1 = $rest\n";
- }
-
- elsif ($name eq "queue_remote_domains")
- {
- print STDOUT "#!!# queue_remote_domains renamed queue_domains\n";
- printf STDOUT ("queue_domains = %s\n", &no_expand_regex($rest));
- }
-
- elsif ($name eq "receiver_unqualified_hosts")
- {
- print STDOUT "#!!# receiver_unqualified_hosts renamed recipient_unqualified_hosts\n";
- printf STDOUT ("recipient_unqualified_hosts = %s\n",
- &no_expand_regex($rest));
- }
-
- elsif ($name eq "remote_sort")
- {
- print STDOUT "#!!# remote_sort renamed remote_sort_domains\n";
- printf STDOUT ("remote_sort_domains = %s\n", &no_expand_regex($rest));
- }
-
- elsif ($name eq "security")
- {
- if ($rest eq "unprivileged")
- {
- print STDOUT "#!!# security=unprivileged changed to deliver_drop_privilege\n";
- print STDOUT "deliver_drop_privilege\n";
- }
- else
- {
- &rubric();
- print STDERR "\n" .
-"** The 'security' option no longer exists.\n";
- }
- }
-
- elsif ($name eq "timestamps_utc")
- {
- print STDOUT "#!!# timestamps_utc changed to use timezone\n";
- print STDOUT "timezone = utc\n";
- }
-
- elsif ($name eq "untrusted_set_sender")
- {
- print STDOUT "#!!# untrusted_set_sender is now a list of what can be set\n";
- print STDOUT "#!!# The default is an empty list.\n";
- if (&bool("untrusted_set_sender"))
- {
- print STDOUT "untrusted_set_sender = *\n";
- }
- }
-
- elsif ($name eq "warnmsg_file")
- {
- print STDOUT "#!!# warnmsg_file renamed warn_message_file\n";
- print STDOUT "warn_message_file = $rest\n";
- }
-
- # Remaining options just get copied unless they are one of those that's
- # a list where any regular expressions have to be escaped.
-
- else
- {
- my($no_expand) = 0;
- foreach $o (@list_options)
- {
- if ($name eq $o)
- {
- $no_expand = 1;
- last;
- }
- }
- &outopt(\%main, $name, $no_expand);
- }
- }
-
-
-# -------- The ACL configuration --------
-
-print STDOUT "\n";
-print STDOUT "#!!#######################################################!!#\n";
-print STDOUT "#!!# This new section of the configuration contains ACLs #!!#\n";
-print STDOUT "#!!# (Access Control Lists) derived from the Exim 3 #!!#\n";
-print STDOUT "#!!# policy control options. #!!#\n";
-print STDOUT "#!!#######################################################!!#\n";
-
-print STDOUT "\n";
-print STDOUT "#!!# These ACLs are crudely constructed from Exim 3 options.\n";
-print STDOUT "#!!# They are almost certainly not optimal. You should study\n";
-print STDOUT "#!!# them and rewrite as necessary.\n";
-
-print STDOUT "\nbegin acl\n\n";
-
-
-# Output an ACL for use after the RCPT command. This combines all the previous
-# policy checking options.
-
-print STDOUT "#!!# ACL that is used after the RCPT command\n";
-print STDOUT "check_recipient:\n";
-
-print STDOUT " # Exim 3 had no checking on -bs messages, so for compatibility\n";
-print STDOUT " # we accept if the source is local SMTP (i.e. not over TCP/IP).\n";
-print STDOUT " # We do this by testing for an empty sending host field.\n";
-print STDOUT " accept hosts = :\n";
-
-if (defined $main{"tls_verify_ciphers"})
- {
- print STDOUT " deny ";
- print STDOUT "hosts = $main{'tls_verify_hosts'}\n "
- if defined $main{"tls_verify_hosts"};
- print STDOUT " encrypted = *\n ";
- print STDOUT "!encrypted = $main{'tls_verify_ciphers'}\n";
- }
-
-print STDOUT " deny hosts = +auth_hosts\n" .
- " message = authentication required\n" .
- " !authenticated = *\n"
- if defined $main{"auth_hosts"};
-
-print STDOUT " deny hosts = +tls_hosts\n" .
- " message = encryption required\n" .
- " !encrypted = *\n"
- if defined $main{"tls_hosts"};
-
-printf STDOUT (" accept recipients = %s\n",
- &acl_quote(&sort_address_list($main{"recipients_reject_except"},
- "recipients_reject_except")))
- if defined $main{"recipients_reject_except"};
-
-printf STDOUT (" accept senders = %s\n",
- &acl_quote(&sort_address_list($main{"recipients_reject_except_senders"},
- "recipients_reject_except_senders")))
- if defined $main{"recipients_reject_except_senders"};
-
-printf STDOUT (" deny hosts = %s\n", &acl_quote($main{"host_reject"}))
- if defined $main{"host_reject"};
-
-printf STDOUT (" deny hosts = %s\n",
- &acl_quote($main{"host_reject_recipients"}))
- if defined $main{"host_reject_recipients"};
-
-if (defined $main{"rbl_domains"})
- {
- my($msg) = "message = host is listed in \$dnslist_domain\n ";
- my($hlist) = (defined $main{"rbl_hosts"})?
- "hosts = +rbl_hosts\n " : "";
-
- print STDOUT " accept ${hlist}dnslists = $rbl_accept_domains\n"
- if defined $rbl_accept_domains;
- print STDOUT " deny ${hlist}${msg}dnslists = $rbl_reject_domains\n"
- if defined $rbl_reject_domains;
- print STDOUT " warn ${hlist}" .
- "message = X-Warning: \$sender_host_address is listed at \$dnslist_domain\n" .
- " dnslists = $rbl_warn_domains\n"
- if defined $rbl_warn_domains;
-
- if (defined $main{"host_accept_relay"})
- {
- $hlist .= "hosts = !+relay_hosts\n ";
- print STDOUT " accept ${hlist}dnslists = $rbl_accept_skiprelay\n"
- if defined $rbl_accept_skiprelay;
- print STDOUT " deny ${hlist}${msg}dnslists = $rbl_reject_skiprelay\n"
- if defined $rbl_reject_skiprelay;
- print STDOUT " warn ${hlist}" .
- "message = X-Warning: \$sender_host_address is listed at \$dnslist_domain\n" .
- " dnslists = $rbl_warn_skiprelay\n"
- if defined $rbl_warn_skiprelay;
- }
- }
-
-printf STDOUT (" deny senders = %s\n",
- &acl_quote(&sort_address_list($main{"sender_reject"}, "sender_reject")))
- if defined $main{"sender_reject"};
-
-printf STDOUT (" deny senders = %s\n",
- &acl_quote(&sort_address_list($main{"sender_reject_recipients"},
- "sender_reject_recipients")))
- if defined $main{"sender_reject_recipients"};
-
-if (&bool("sender_verify"))
- {
- if (defined $main{"sender_verify_hosts_callback"} &&
- defined $main{"sender_verify_callback_domains"})
- {
- printf STDOUT (" deny hosts = %s\n",
- &acl_quote($main{"sender_verify_hosts_callback"}));
- printf STDOUT (" sender_domains = %s\n",
- &acl_quote($main{"sender_verify_callback_domains"}));
- print STDOUT " !verify = sender/callout";
- print STDOUT "=$main{\"sender_verify_callback_timeout\"}"
- if defined $main{"sender_verify_callback_timeout"};
- print STDOUT "\n";
- }
-
- if (defined $main{"sender_verify_hosts"})
- {
- printf STDOUT (" deny hosts = %s\n",
- &acl_quote($main{"sender_verify_hosts"}));
- print STDOUT " !verify = sender\n";
- }
- else
- {
- print STDOUT " require verify = sender\n";
- }
- }
-
-if (&bool("receiver_verify"))
- {
- print STDOUT " deny message = unrouteable address\n";
- printf STDOUT (" recipients = %s\n",
- &acl_quote(&sort_address_list($main{"receiver_verify_addresses"},
- "receiver_verify_addresses")))
- if defined $main{"receiver_verify_addresses"};
- printf STDOUT (" hosts = %s\n",
- &acl_quote($main{"receiver_verify_hosts"}))
- if defined $main{"receiver_verify_hosts"};
- printf STDOUT (" senders = %s\n",
- &acl_quote(&sort_address_list($main{"receiver_verify_senders"},
- "receiver_verify_senders")))
- if defined $main{"receiver_verify_senders"};
- print STDOUT " !verify = recipient\n";
- }
-
-print STDOUT " accept domains = +local_domains\n"
- if $local_domains !~ /^\s*$/;
-
-print STDOUT " accept domains = +relay_domains\n"
- if $relay_domains !~ /^\s*$/;
-
-if (defined $main{"host_accept_relay"})
- {
- if (defined $main{"sender_address_relay"})
- {
- if (defined $main{"sender_address_relay_hosts"})
- {
- printf STDOUT (" accept hosts = %s\n",
- &acl_quote($main{"sender_address_relay_hosts"}));
- print STDOUT " endpass\n";
- print STDOUT " message = invalid sender\n";
- printf STDOUT (" senders = %s\n",
- &acl_quote(&sort_address_list($main{"sender_address_relay"},
- "sender_address_relay")));
- print STDOUT " accept hosts = +relay_hosts\n";
- }
- else
- {
- print STDOUT " accept hosts = +relay_hosts\n";
- print STDOUT " endpass\n";
- print STDOUT " message = invalid sender\n";
- printf STDOUT (" senders = %s\n",
- &acl_quote(&sort_address_list($main{"sender_address_relay"},
- "sender_address_relay")));
- }
- }
- else
- {
- print STDOUT " accept hosts = +relay_hosts\n";
- }
- }
-
-print STDOUT " accept hosts = +auth_relay_hosts\n" .
- " endpass\n" .
- " message = authentication required\n" .
- " authenticated = *\n"
- if defined $main{"host_auth_accept_relay"};
-
-print STDOUT " accept hosts = +tls_relay_hosts\n" .
- " endpass\n" .
- " message = encryption required\n" .
- " encrypted = *\n"
- if defined $main{"tls_host_accept_relay"};
-
-print STDOUT " deny message = relay not permitted\n\n";
-
-
-# Output an ACL for use after the DATA command. This is concerned with
-# header checking.
-
-print STDOUT "#!!# ACL that is used after the DATA command\n";
-print STDOUT "check_message:\n";
-
-# Default for headers_checks_fail is true
-
-if (!defined $main{"headers_checks_fail"} ||
- $main{"headers_checks_fail"} eq "true")
- {
- print STDOUT " require verify = header_syntax\n"
- if &bool("headers_check_syntax");
- print STDOUT " require verify = header_sender\n"
- if &bool("headers_sender_verify");
- print STDOUT " accept senders = !:\n require verify = header_sender\n"
- if &bool("headers_sender_verify_errmsg");
- }
-else
- {
- print STDOUT " warn !verify = header_syntax\n"
- if &bool("headers_check_syntax");
- print STDOUT " warn !verify = header_sender\n"
- if &bool("headers_sender_verify");
- print STDOUT " accept senders = !:\n warn !verify = header_sender\n"
- if &bool("headers_sender_verify_errmsg");
- }
-
-print STDOUT " accept\n\n";
-
-
-# Output an ACL for AUTH if required
-
-if (defined $main{"auth_over_tls_hosts"})
- {
- print STDOUT "#!!# ACL that is used after the AUTH command\n" .
- "check_auth:\n" .
- " accept hosts = +auth_over_tls_hosts\n" .
- " endpass\n" .
- " message = STARTTLS required before AUTH\n" .
- " encrypted = *\n" .
- " accept\n";
- }
-
-
-# Output ACLs for ETRN, EXPN, and VRFY if required
-
-if (defined $main{"smtp_etrn_hosts"})
- {
- print STDOUT "#!!# ACL that is used after the ETRN command\n" .
- "check_etrn:\n";
- print STDOUT " deny hosts = +auth_hosts\n" .
- " message = authentication required\n" .
- " !authenticated = *\n"
- if defined $main{"auth_hosts"};
- print STDOUT " accept hosts = $main{\"smtp_etrn_hosts\"}\n\n";
- }
-
-if (defined $main{"smtp_expn_hosts"})
- {
- print STDOUT "#!!# ACL that is used after the EXPN command\n" .
- "check_expn:\n";
- print STDOUT " deny hosts = +auth_hosts\n" .
- " message = authentication required\n" .
- " !authenticated = *\n"
- if defined $main{"auth_hosts"};
- print STDOUT " accept hosts = $main{\"smtp_expn_hosts\"}\n\n";
- }
-
-if (&bool("smtp_verify"))
- {
- print STDOUT "#!!# ACL that is used after the VRFY command\n" .
- "check_vrfy:\n";
- print STDOUT " deny hosts = +auth_hosts\n" .
- " message = authentication required\n" .
- " !authenticated = *\n"
- if defined $main{"auth_hosts"};
- print STDOUT " accept\n\n";
- }
-
-# -------- The authenticators --------
-
-$started = 0;
-for ($i = $auth_start; $i < $clen; $i++)
- {
- if (!$started)
- {
- if ($c[$i] !~ /^\s*(#|$)/)
- {
- print STDOUT "\nbegin authenticators\n\n";
- $started = 1;
- }
- }
- print STDOUT "$c[$i]\n";
- }
-
-
-# -------- Rewrite section --------
-
-$started = 0;
-for ($i = $rewrite_start; $i < $clen && $i < $auth_start - 1; $i++)
- {
- if (!$started)
- {
- if ($c[$i] !~ /^\s*(#|$)/)
- {
- print STDOUT "\nbegin rewrite\n\n";
- $started = 1;
- }
- }
- &print_no_expand($c[$i]);
- }
-
-
-# -------- The routers configuration --------
-
-# The new routers configuration is created out of the old directors and routers
-# configuration. We put the old routers first, adding a "domains" option to
-# any that don't have one, to make them select the domains that do not match
-# the original local_domains. The routers get modified as necessary, and the
-# final one has "no_more" set, unless it has conditions. In that case we have
-# to add an extra router to be sure of failing all non-local addresses that
-# fall through. We do this also if there are no routers at all. The old
-# directors follow, modified as required.
-
-$prefix = "r.";
-undef @comments;
-
-print STDOUT "\n";
-print STDOUT "#!!#######################################################!!#\n";
-print STDOUT "#!!# Here follow routers created from the old routers, #!!#\n";
-print STDOUT "#!!# for handling non-local domains. #!!#\n";
-print STDOUT "#!!#######################################################!!#\n";
-
-print STDOUT "\nbegin routers\n\n";
-
-for ($i = $router_start; $i < $clen; $i++)
- {
- $type = &checkline($c[$i]);
- last if $type eq "end";
-
- if ($type eq "comment") { push(@comments, "$c[$i]\n"); next; }
-
- # When we hit the start of a driver, modify its options as necessary,
- # and then output it from the stored option settings, having first output
- # and previous comments.
-
- if ($type eq "driver")
- {
- print STDOUT shift @comments while scalar(@comments) > 0;
-
- $hash = $driverlist{"$prefix$name"};
- $driver = $$hash{"driver"};
- print STDOUT "$name:\n";
-
- $add_no_more =
- ! defined $$hash{"domains"} &&
- ! defined $$hash{"local_parts"} &&
- ! defined $$hash{"senders"} &&
- ! defined $$hash{"condition"} &&
- ! defined $$hash{"require_files"} &&
- (!defined $$hash{"verify_only"} || $$hash{"verify_only"} eq "false") &&
- (!defined $$hash{"verify"} || $$hash{"verify"} eq "true");
-
- # Create a "domains" setting if there isn't one, unless local domains
- # was explicitly empty.
-
- $$hash{"domains"} = "! +local_domains"
- if !defined $$hash{"domains"} && $local_domains !~ /^\s*$/;
-
- # If the router had a local_parts setting, add caseful_local_part
-
- $$hash{"caseful_local_part"} = "true" if defined $$hash{"local_parts"};
-
- # If the router has "self=local" set, change it to "self=pass", and
- # set pass_router to the router that was the first director. Change the
- # obsolete self settings of "fail_hard" and "fail_soft" to "fail" and
- # "pass".
-
- if (defined $$hash{"self"})
- {
- if ($$hash{"self"} eq "local")
- {
- $$hash{"self"} = "pass";
- $$hash{"pass_router"} = $first_director;
- }
- elsif ($$hash{"self"} eq "fail_hard")
- {
- $$hash{"self"} = "fail";
- }
- elsif ($$hash{"self"} eq "fail_soft")
- {
- $$hash{"self"} = "pass";
- }
- }
-
- # If the router had a require_files setting, check it for user names
- # and colons that are part of expansion items
-
- if (defined $$hash{"require_files"})
- {
- &check_require($$hash{"require_files"}, "'$name' router");
- if (($$hash{"require_files"} =~ s/(\$\{\w+):/$1::/g) > 0 ||
- ($$hash{"require_files"} =~ s/ldap:/ldap::/g) > 0)
- {
- &rubric();
- print STDERR "\n" .
-"*** A setting of require_files in the $name router contains\n" .
-" a colon in what appears to be an expansion item. In Exim 3, the\n" .
-" whole string was expanded before splitting the list, but in Exim 4\n" .
-" each item is expanded separately, so colons that are not list\n" .
-" item separators have to be doubled. One or more such colons in this\n" .
-" list have been doubled as a precaution. Please check the result.\n";
- }
- }
-
- # If the router had a "senders" setting, munge the address list
-
- $$hash{"senders"} = &sort_address_list($$hash{"senders"}, "senders")
- if defined $$hash{"senders"};
-
- # ---- Changes to domainlist router ----
-
- if ($driver eq "domainlist")
- {
- &abolished($hash, "A domainlist router",
- "modemask", "owners", "owngroups",
- "qualify_single", "search_parents");
-
- # The name has changed
-
- $$hash{"driver"} = "manualroute";
-
- # Turn "route_file", "route_query" and "route_queries" into lookups for
- # route_data.
-
- if (defined $$hash{"route_file"})
- {
- $$hash{"route_data"} = "\${lookup\{\$domain\}$$hash{'search_type'}" .
- "\{$$hash{'route_file'}\}\}";
- }
- elsif (defined $$hash{"route_query"})
- {
- $$hash{"route_data"} = "\${lookup $$hash{'search_type'}" .
- "\{" . &unquote($$hash{'route_query'}) . "\}\}";
- }
- elsif (defined $$hash{"route_queries"})
- {
- $endkets = 0;
- $$hash{"route_data"} = "";
- $route_queries = $$hash{'route_queries'};
- $route_queries =~ s/^"(.*)"$/$1/s;
- $route_queries =~ s/::/++colons++/g;
- @qq = split(/:/, $route_queries);
-
- foreach $q (@qq)
- {
- $q =~ s/\+\+colons\+\+/:/g;
- $q =~ s/^\s+//;
- $q =~ s/\s+$//;
- if ($endkets > 0)
- {
- $$hash{"route_data"} .= "\\\n {";
- $endkets++;
- }
- $$hash{"route_data"} .= "\${lookup $$hash{'search_type'} \{$q\}\{\$value\}";
- $endkets++;
- }
-
- $$hash{"route_data"} .= "}" x $endkets;
- }
-
- delete $$hash{"route_file"};
- delete $$hash{"route_query"};
- delete $$hash{"route_queries"};
- delete $$hash{"search_type"};
-
- # But we can't allow both route_data and route_list
-
- if (defined $$hash{"route_data"} && defined $$hash{"route_list"})
- {
- &rubric();
- print STDERR "\n" .
-"** An Exim 3 'domainlist' router called '$name' contained a 'route_list'\n" .
-" option as well as a setting of 'route_file', 'route_query', or\n" .
-" 'route_queries'. The latter has been turned into a 'route_data' setting,\n".
-" but in Exim 4 you can't have both 'route_data' and 'route_list'. You'll\n" .
-" have to rewrite this router; in the meantime, 'route_list' has been\n" .
-" omitted.\n";
- print STDOUT "#!!# route_list option removed\n";
- delete $$hash{"route_list"};
- }
-
- # Change bydns_a into bydns in a route_list; also bydns_mx, but that
- # works differently.
-
- if (defined $$hash{"route_list"})
- {
- $$hash{"route_list"} =~ s/bydns_a/bydns/g;
- if ($$hash{"route_list"} =~ /bydns_mx/)
- {
- $$hash{"route_list"} =~ s/bydns_mx/bydns/g;
- &rubric();
- print STDERR "\n" .
-"*** An Exim 3 'domainlist' router called '$name' contained a 'route_list'\n" .
-" option which used 'bydns_mx'. This feature no longer exists in Exim 4.\n" .
-" It has been changed to 'bydns', but it won't have the same effect,\n" .
-" because it will look for A rather than MX records. Use the 'dnslookup'\n" .
-" router to do MX lookups - if you want to override the hosts found from\n" .
-" MX records, you should route to a special 'smtp' transport which has\n" .
-" both 'hosts' and 'hosts_override' set.\n";
- }
- }
-
- # Arrange to not expand regex
-
- $$hash{"route_list"} = &no_expand_regex($$hash{"route_list"}, ";")
- if (defined $$hash{"route_list"})
- }
-
-
- # ---- Changes to iplookup router ----
-
- elsif ($driver eq "iplookup")
- {
- &renamed($hash, "service", "port");
- }
-
-
- # ---- Changes to lookuphost router ----
-
- elsif ($driver eq "lookuphost")
- {
- $$hash{"driver"} = "dnslookup";
-
- if (defined $$hash{"gethostbyname"})
- {
- &rubric();
- print STDERR "\n" .
-"** An Exim 3 'lookuphost' router called '$name' used the 'gethostbyname'\n" .
-" option, which no longer exists. You will have to rewrite it.\n";
- print STDOUT "#!!# gethostbyname option removed\n";
- delete $$hash{"gethostbyname"};
- }
-
- $$hash{"mx_domains"} = &no_expand_regex($$hash{"mx_domains"})
- if defined $$hash{"mx_domains"};
- }
-
-
- # ---- Changes to the queryprogram router ----
-
- elsif ($driver eq "queryprogram")
- {
- &rubric();
- print STDERR "\n" .
-"** The configuration contains a 'queryprogram' router. Please note that\n" .
-" the specification for the text that is returned by the program run\n" .
-" by this router has changed in Exim 4. You will need to modify your\n" .
-" program.\n";
-
- if (!defined $$hash{'command_user'})
- {
- &rubric();
- print STDERR "\n" .
-"** The 'queryprogram' router called '$name' does not have a setting for\n" .
-" the 'command_user' option. This is mandatory in Exim 4. A setting of\n" .
-" 'nobody' has been created.\n";
- $$hash{"command_user"} = "nobody";
- }
- }
-
-
- # -------------------------------------
-
- # Output the router's option settings
-
- &outdriver($hash);
- next;
- }
-
- # Skip past any continuation lines for an option setting
- while ($c[$i] =~ /\\\s*$/s && $i < $clen - 1)
- {
- $i++;
- $i++ while ($c[$i] =~ /^\s*#/);
- }
- }
-
-# Add "no_more" to the final driver from the old routers, provided it had no
-# conditions. Otherwise, or if there were no routers, make up one to fail all
-# non-local domains.
-
-if ($add_no_more)
- {
- print STDOUT " no_more\n";
- print STDOUT shift @comments while scalar(@comments) > 0;
- }
-else
- {
- print STDOUT shift @comments while scalar(@comments) > 0;
- print STDOUT "\n#!!# This new router is put here to fail all domains that\n";
- print STDOUT "#!!# were not in local_domains in the Exim 3 configuration.\n\n";
- print STDOUT "fail_remote_domains:\n";
- print STDOUT " driver = redirect\n";
- print STDOUT " domains = ! +local_domains\n";
- print STDOUT " allow_fail\n";
- print STDOUT " data = :fail: unrouteable mail domain \"\$domain\"\n\n";
- }
-
-# Now copy the directors, making appropriate changes
-
-print STDOUT "\n";
-print STDOUT "#!!#######################################################!!#\n";
-print STDOUT "#!!# Here follow routers created from the old directors, #!!#\n";
-print STDOUT "#!!# for handling local domains. #!!#\n";
-print STDOUT "#!!#######################################################!!#\n";
-
-$prefix = "d.";
-for ($i = $director_start; $i < $clen; $i++)
- {
- $type = &checkline($c[$i]);
- last if $type eq "end";
-
- if ($type eq "comment") { print STDOUT "$c[$i]\n"; next; }
-
- undef $second_router;
-
- if ($type eq "driver")
- {
- $hash = $driverlist{"$prefix$name"};
- $driver = $$hash{"driver"};
- print STDOUT "$name:\n";
-
- $$hash{"caseful_local_part"} = "true" if $add_caseful_local_part;
-
- if (defined $$hash{"local_parts"} &&
- (defined $$hash{"prefix"} || defined $hash{"suffix"}))
- {
- &rubric();
- print STDERR "\n" .
-"** The Exim 3 configuration contains a director called '$name' which has\n" .
-" 'local_parts' set, together with either or both of 'prefix' and 'suffix'\n".
-" This combination has a different effect in Exim 4, where the affix\n" .
-" is removed *before* 'local_parts' is tested. You will probably need\n" .
-" to make changes to this driver.\n";
- }
-
- &renamed($hash, "prefix", "local_part_prefix");
- &renamed($hash, "prefix_optional", "local_part_prefix_optional");
- &renamed($hash, "suffix", "local_part_suffix");
- &renamed($hash, "suffix_optional", "local_part_suffix_optional");
- &renamed($hash, "new_director", "redirect_router");
-
- &handle_current_and_home_directory($hash, $driver, $name);
-
- # If the director had a require_files setting, check it for user names
- # and colons that are part of expansion items
-
- if (defined $$hash{"require_files"})
- {
- &check_require($$hash{"require_files"}, "'$name' director");
- if (($$hash{"require_files"} =~ s/(\$\{\w+):/$1::/g) > 0 ||
- ($$hash{"require_files"} =~ s/ldap:/ldap::/g) > 0)
- {
- &rubric();
- print STDERR "\n" .
-"*** A setting of require_files in the $name director contains\n" .
-" a colon in what appears to be an expansion item. In Exim 3, the\n" .
-" whole string was expanded before splitting the list, but in Exim 4\n" .
-" each item is expanded separately, so colons that are not list\n" .
-" item separators have to be doubled. One or more such colons in this\n" .
-" list have been doubled as a precaution. Please check the result.\n";
- }
- }
-
- # If the director had a "senders" setting, munge the address list
-
- $$hash{"senders"} = &sort_address_list($$hash{"senders"}, "senders")
- if defined $$hash{"senders"};
-
- # ---- Changes to aliasfile director ----
-
- if ($driver eq "aliasfile")
- {
- &abolished($hash, "An aliasfile director",
- "directory2_transport", "freeze_missing_include",
- "modemask", "owners", "owngroups");
-
- $$hash{"driver"} = "redirect";
-
- $key = "\$local_part";
- $key = "\$local_part\@\$domain"
- if defined $$hash{"include_domain"} &&
- $$hash{"include_domain"} eq "true";
- delete $$hash{"include_domain"};
-
- if (defined $$hash{"forbid_special"} && $$hash{"forbid_special"} eq "true")
- {
- $$hash{"forbid_blackhole"} = "true";
- }
- else
- {
- $$hash{"allow_defer"} = "true";
- $$hash{"allow_fail"} = "true";
- }
- delete $$hash{"forbid_special"};
-
- # Deal with "file", "query", or "queries"
-
- if (defined $$hash{"file"})
- {
- $$hash{"data"} =
- "\$\{lookup\{$key\}$$hash{'search_type'}\{$$hash{'file'}\}\}";
- if (defined $$hash{"optional"} && $$hash{"optional"} eq "true")
- {
- $$hash{"data"} =
- "\$\{if exists\{$$hash{'file'}\}\{$$hash{'data'}\}\}";
- }
- delete $$hash{"optional"};
- }
- elsif (defined $$hash{"query"})
- {
- &abolished($hash, "An aliasfile director", "optional");
- $$hash{"data"} = "\${lookup $$hash{'search_type'} " .
- "\{" . &unquote($$hash{'query'}) . "\}\}";
- }
- else # Must be queries
- {
- &abolished($hash, "An aliasfile director", "optional");
- $endkets = 0;
- $$hash{"data"} = "";
- $queries = $$hash{'queries'};
- $queries =~ s/^"(.*)"$/$1/s;
- $queries =~ s/::/++colons++/g;
- @qq = split(/:/, $queries);
-
- foreach $q (@qq)
- {
- $q =~ s/\+\+colons\+\+/:/g;
- $q =~ s/^\s+//;
- $q =~ s/\s+$//;
- if ($endkets > 0)
- {
- $$hash{"data"} .= "\\\n {";
- $endkets++;
- }
- $$hash{"data"} .= "\${lookup $$hash{'search_type'} \{$q\}\{\$value\}";
- $endkets++;
- }
-
- $$hash{"data"} .= "}" x $endkets;
- }
-
- $$hash{"data"} = "\${expand:$$hash{'data'}\}"
- if (defined $$hash{"expand"} && $$hash{"expand"} eq "true");
-
- delete $$hash{"expand"};
- delete $$hash{"file"};
- delete $$hash{"query"};
- delete $$hash{"queries"};
- delete $$hash{"search_type"};
-
- # Turn aliasfile + transport into accept + condition
-
- if (defined $$hash{'transport'})
- {
- &rubric();
- if (!defined $$hash{'condition'})
- {
- print STDERR "\n" .
-"** The Exim 3 configuration contains an aliasfile director called '$name',\n".
-" which has 'transport' set. This has been turned into an 'accept' router\n".
-" with a 'condition' setting, but should be carefully checked.\n";
- $$hash{'driver'} = "accept";
- $$hash{'condition'} =
- "\$\{if eq \{\}\{$$hash{'data'}\}\{no\}\{yes\}\}";
- delete $$hash{'data'};
- delete $$hash{'allow_defer'};
- delete $$hash{'allow_fail'};
- }
- else
- {
- print STDERR "\n" .
-"** The Exim 3 configuration contains an aliasfile director called '$name',\n".
-" which has 'transport' set. This cannot be turned into an 'accept' router\n".
-" with a 'condition' setting, because there is already a 'condition'\n" .
-" setting. It has been left as 'redirect' with a transport, which is\n" .
-" invalid - you must sort this one out.\n";
- }
- }
- }
-
-
- # ---- Changes to forwardfile director ----
-
- elsif ($driver eq "forwardfile")
- {
- &abolished($hash, "A forwardfile director",
- "check_group", "directory2_transport",
- "freeze_missing_include", "match_directory",
- "seteuid");
-
- &renamed($hash, "filter", "allow_filter");
-
- $$hash{"driver"} = "redirect";
- $$hash{"check_local_user"} = "true"
- if !defined $$hash{"check_local_user"};
-
- if (defined $$hash{"forbid_pipe"} && $$hash{"forbid_pipe"} eq "true")
- {
- print STDOUT "#!!# forbid_filter_run added because forbid_pipe is set\n";
- $$hash{"forbid_filter_run"} = "true";
- }
-
- if (defined $$hash{'allow_system_actions'} &&
- $$hash{'allow_system_actions'} eq 'true')
- {
- $$hash{'allow_freeze'} = "true";
- }
- delete $$hash{'allow_system_actions'};
-
- # If file_directory is defined, use it to qualify relative paths; if not,
- # and check_local_user is defined, use $home. Remove file_directory from
- # the output.
-
- $dir = "";
- if (defined $$hash{"file_directory"})
- {
- $dir = $$hash{"file_directory"} . "/";
- delete $$hash{"file_directory"};
- }
- elsif ($$hash{"check_local_user"} eq "true")
- {
- $dir = "\$home/";
- }
-
- # If it begins with an upper case letter, guess that this is really
- # a macro.
-
- if (defined $$hash{"file"} && $$hash{"file"} !~ /^[\/A-Z]/)
- {
- $$hash{"file"} = $dir . $$hash{"file"};
- }
- }
-
-
- # ---- Changes to localuser director ----
-
- elsif ($driver eq "localuser")
- {
- &abolished($hash, "A localuser director", "match_directory");
- $$hash{"driver"} = "accept";
- $$hash{"check_local_user"} = "true";
- }
-
-
- # ---- Changes to smartuser director ----
-
- elsif ($driver eq "smartuser")
- {
- &abolished($hash, "A smartuser director", "panic_expansion_fail");
-
- $transport = $$hash{"transport"};
- $new_address = $$hash{"new_address"};
-
- if (defined $transport && defined $new_address)
- {
- &rubric();
- print STDERR "\n" .
-"** The Exim 3 configuration contains a smartuser director called '$name',\n".
-" which has both 'transport' and 'new_address' set. This has been turned\n".
-" into two routers for Exim 4. However, if the new address contains a\n" .
-" reference to \$local_part, this won't work correctly. In any case, you\n".
-" may be able to make it tidier by rewriting.\n";
- $$hash{"driver"} = "redirect";
- $$hash{"data"} = $new_address;
- $$hash{"redirect_router"} = "${name}_part2";
-
- $second_router = "\n".
- "#!!# This router is invented to go with the previous one because\n".
- "#!!# in Exim 4 you can't have a change of address and a transport\n".
- "#!!# setting in the same router as you could in Exim 3.\n\n" .
- "${name}_part2:\n".
- " driver = accept\n".
- " condition = \$\{if eq\{\$local_part@\$domain\}" .
- "\{$new_address\}\{yes\}\{no\}\}\n".
- " transport = $$hash{'transport'}\n";
-
- delete $$hash{"new_address"};
- delete $$hash{"transport"};
- }
- elsif (defined $new_address)
- {
- $$hash{"driver"} = "redirect";
- $$hash{"data"} = $new_address;
- $$hash{"allow_defer"} = "true";
- $$hash{"allow_fail"} = "true";
- delete $$hash{"new_address"};
- }
- else # Includes the case of neither set (verify_only)
- {
- $$hash{"driver"} = "accept";
- if (defined $$hash{"rewrite"})
- {
- &rubric();
- print STDERR "\n" .
-"** The Exim 3 configuration contains a setting of the 'rewrite' option on\n".
-" a smartuser director called '$name', but this director does not have\n".
-" a setting of 'new_address', so 'rewrite' has no effect. The director\n".
-" has been turned into an 'accept' router, and 'rewrite' has been discarded.";
- delete $$hash{"rewrite"};
- }
- }
- }
-
-
- # -------------------------------------
-
- # For ex-directors that don't have check_local_user set, add
- # retry_use_local_part to imitate what Exim 3 would have done.
-
- $$hash{"retry_use_local_part"} = "true"
- if (!defined $$hash{"check_local_user"} ||
- $$hash{"check_local_user"} eq "false") ;
-
- # Output the router's option settings
-
- &outdriver($hash);
-
- # Output an auxiliary router if one is needed
-
- print STDOUT $second_router if defined $second_router;
-
- next;
- }
-
- # Skip past any continuation lines for an option setting
- while ($c[$i] =~ /\\\s*$/s)
- {
- $i++;
- $i++ while ($c[$i] =~ /^\s*#/);
- }
- }
-
-
-
-# -------- The transports configuration --------
-
-$started = 0;
-$prefix = "t.";
-for ($i = $transport_start; $i < $clen; $i++)
- {
- $type = &checkline($c[$i]);
- last if $type eq "end";
-
- if ($type eq "comment") { print STDOUT "$c[$i]\n"; next; }
-
- if (!$started)
- {
- print STDOUT "begin transports\n\n";
- $started = 1;
- }
-
- if ($type eq "driver")
- {
- $hash = $driverlist{"$prefix$name"};
- $driver = $$hash{"driver"};
- print STDOUT "$name:\n";
-
- # ---- Changes to the appendfile transport ----
-
- if ($driver eq "appendfile")
- {
- &renamed($hash, "prefix", "message_prefix");
- &renamed($hash, "suffix", "message_suffix");
- &abolished($hash, "An appendfile transport",
- "require_lockfile");
- &handle_batch_and_bsmtp($hash);
- if (defined $$hash{"from_hack"} && $$hash{"from_hack"} eq "false")
- {
- print STDOUT "#!!# no_from_hack replaced by check_string\n";
- $$hash{"check_string"} = "";
- }
- delete $$hash{"from_hack"};
- }
-
- # ---- Changes to the lmtp transport ----
-
- elsif ($driver eq "lmtp")
- {
- if (defined $$hash{"batch"} && $$hash{"batch"} ne "none")
- {
- $$hash{"batch_max"} = "100" if !defined $$hash{"batch_max"};
- $$hash{"batch_id"} = "\$domain" if $$hash{"batch"} eq "domain";
- }
- else
- {
- $$hash{"batch_max"} = "1" if defined $$hash{"batch_max"};
- }
- delete $$hash{"batch"};
- }
-
- # ---- Changes to the pipe transport ----
-
- elsif ($driver eq "pipe")
- {
- &renamed($hash, "prefix", "message_prefix");
- &renamed($hash, "suffix", "message_suffix");
- &handle_batch_and_bsmtp($hash);
- if (defined $$hash{"from_hack"} && $$hash{"from_hack"} eq "false")
- {
- print STDOUT "#!!# no_from_hack replaced by check_string\n";
- $$hash{"check_string"} = "";
- }
- delete $$hash{"from_hack"};
- }
-
- # ---- Changes to the smtp transport ----
-
- elsif ($driver eq "smtp")
- {
- &abolished($hash, "An smtp transport", "mx_domains");
- &renamed($hash, "service", "port");
- &renamed($hash, "tls_verify_ciphers", "tls_require_ciphers");
- &renamed($hash, "authenticate_hosts", "hosts_try_auth");
-
- if (defined $$hash{"batch_max"})
- {
- print STDOUT "#!!# batch_max renamed connection_max_messages\n";
- $$hash{"connection_max_messages"} = $$hash{"batch_max"};
- delete $$hash{"batch_max"};
- }
-
- foreach $o ("hosts_try_auth", "hosts_avoid_tls", "hosts_require_tls",
- "mx_domains", "serialize_hosts")
- {
- $$hash{$o} = &no_expand_regex($$hash{$o}) if defined $$hash{$o};
- }
- }
-
- &outdriver($driverlist{"$prefix$name"});
- next;
- }
-
- # Skip past any continuation lines for an option setting
- while ($c[$i] =~ /\\\s*$/s)
- {
- $i++;
- $i++ while ($c[$i] =~ /^\s*#/);
- }
- }
-
-
-# -------- The retry configuration --------
-
-$started = 0;
-for ($i = $retry_start; $i < $clen && $i < $rewrite_start - 1; $i++)
- {
- if (!$started)
- {
- if ($c[$i] !~ /^\s*(#|$)/)
- {
- print STDOUT "\nbegin retry\n\n";
- $started = 1;
- }
- }
- &print_no_expand($c[$i]);
- }
-
-print STDOUT "\n# End of Exim 4 configuration\n";
-
-print STDERR "\n*******************************************************\n";
-print STDERR "***** Please review the generated file carefully. *****\n";
-print STDERR "*******************************************************\n\n";
-
-# End of convert4r4
-