aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2007-05-01 07:59:58 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2007-05-01 07:59:58 +0000
commit732036d9d146940806635402ce7a208fa847e12f (patch)
treeddf53ac4e9d65429e86479f6d918983dda74aac1
parent4dd5e7bb0306f5225b8e307dacde98807d3676bb (diff)
downloadmailfromd-git-alpha_3_1_91_berkeley_txn.tar.gz
mailfromd-git-alpha_3_1_91_berkeley_txn.tar.bz2
git-svn-id: file:///svnroot/mailfromd/branches/alpha_3_1_91_berkeley_txn@1401 7a8a7f39-df28-0410-adc6-e0d955640f24
-rw-r--r--ChangeLog8
-rw-r--r--NEWS28
-rw-r--r--doc/mailfromd.texi566
-rw-r--r--doc/mtasim.texi8
-rw-r--r--gacopyz/gacopyz.h7
-rw-r--r--gacopyz/log.c20
-rw-r--r--gacopyz/smfi.c14
-rw-r--r--src/bi_db.m424
-rw-r--r--src/bi_io.m42
-rw-r--r--src/cache.c29
-rw-r--r--src/dnscache.c5
-rw-r--r--src/engine.c12
-rw-r--r--src/gram.y132
-rw-r--r--src/lex.l2
-rw-r--r--src/mailfromd.h6
-rw-r--r--src/main.c22
-rw-r--r--src/prog.c12
-rw-r--r--src/rate.c1
18 files changed, 718 insertions, 180 deletions
diff --git a/ChangeLog b/ChangeLog
index 3ac6ab6d..6cd84276 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2007-05-01 Sergey Poznyakoff <gray@gnu.org.ua>
+
+ * src/lex.l, src/engine.c, src/dnscache.c, src/gram.y,
+ src/mailfromd.h, src/cache.c, src/prog.c, src/bi_io.m4,
+ src/main.c, src/rate.c, src/bi_db.m4, doc/mailfromd.texi,
+ doc/mtasim.texi, gacopyz/smfi.c, gacopyz/gacopyz.h, gacopyz/log.c,
+ NEWS: Port r1400 from trunk
+
2007-04-25 Sergey Poznyakoff <gray@gnu.org.ua>
Synchronize with the trunk
diff --git a/NEWS b/NEWS
index ee23f495..0bd3c443 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-Mailfromd NEWS -- history of user-visible changes. 2007-04-25
+Mailfromd NEWS -- history of user-visible changes. 2007-04-27
Copyright (C) 2005, 2006, 2007 Sergey Poznyakoff
See the end of file for copying conditions.
@@ -17,6 +17,32 @@ useful in automated test cases.
See the documentation, chapter `mtasim'.
+* `begin'/`end' handlers
+
+ The `begin' and `end' special handlers may be used to
+supply startup and cleanup code for the filter program.
+
+ The `begin' special handler is executed once for each
+SMTP session, after the connection has been established but
+before the first milter handler has been called. Similarly, an
+`end' handler is executed exactly once, after the connection has
+been closed. Neither of handlers takes any arguments.
+
+ See the documentation, section `begin/end'.
+
+* Cache control
+
+ Use function `db_set_active' to enable or disable given cache
+database. E.g.
+
+ # Disable DNS cache:
+ db_set_active("dns", 0)
+ # Enable it back again:
+ db_set_active("dns", 0)
+
+Similarly, the function `db_get_active' returns a number indicating
+whether the given cache database is used or not.
+
Version 3.1.91, 2007-04-23
diff --git a/doc/mailfromd.texi b/doc/mailfromd.texi
index 6ba94777..741499b1 100644
--- a/doc/mailfromd.texi
+++ b/doc/mailfromd.texi
@@ -93,7 +93,7 @@ documents @command{mailfromd} Version @value{VERSION}.
* MFL:: The Mail Filtering Language.
* Mailfromd Configuration:: Configuring @command{mailfromd}.
* Sendmail Configuration:: Configuring Sendmail to use @command{mailfromd}.
-* mtasim:: MTA simulator.
+* mtasim:: An @acronym{MTA} simulator.
* Reporting Bugs:: How to Report a Bug.
Appendices
@@ -139,6 +139,7 @@ Tutorial
* Testing Filter Scripts::
* Logging and Debugging::
* Runtime errors::
+* Cautions::
Databases
@@ -157,7 +158,8 @@ Mail Filtering Language
* Constants::
* Variables::
* Back references::
-* Handlers::
+* Handlers::
+* begin/end::
* Functions:: Functions.
* Expressions:: Expressions.
* Statements::
@@ -383,14 +385,14 @@ always discarded.
The described method of address verification is called
@dfn{standard} method throughout this document. @command{Mailfromd}
also implements a method we call @dfn{strict}. When using strict
-method, @command{mailfromd} first resolves IP address of sender
+method, @command{mailfromd} first resolves @acronym{IP} address of sender
machine to a fully qualified domain name. Then it obtains MX records
for this machine, and then proceeds with probing as described above.
So, the difference between the two methods is in the set of MX
records that are being probed: standard method queries MXs based on
the sender email domain, strict method works with MXs for the sender
-IP address.
+@acronym{IP} address.
Strict method allows to cut off much larger amount of spam,
although it does have many drawbacks. Returning to our example above,
@@ -408,7 +410,7 @@ urge the remote party to retry sending his/her message later.
@cindex caching @acronym{DNS} requests
After receiving a definite answer, @command{mailfromd} will
cache it in its database, so that next time your @acronym{MTA} receives a
-message from that address (or from the sender IP/email address pair,
+message from that address (or from the sender @acronym{IP}/email address pair,
for strict method), it will not waste its time trying to reach MX
servers again. The records remain in the cache database for a certain
time, after which they are discarded.
@@ -436,7 +438,7 @@ the expiration timeout in your cache database.
@item When verifying the remote address, no attempt to actually
deliver the message is made. If @acronym{MTA} accepts the address,
@command{mailfromd} assumes it is OK. However in reality, mail for a
-remote address can bounce @emph{after} the nearest MTA accepts the
+remote address can bounce @emph{after} the nearest @acronym{MTA} accepts the
recipient address.
This drawback can often be avoided by combining sender address
@@ -993,7 +995,7 @@ more information about the database compaction.
This chapter contains a tutorial introduction, guiding you
through various @command{mailfromd} configurations, starting from the
-simplest ones and proceeding up to the most advanced forms. It omits
+simplest ones and proceeding up to more advanced forms. It omits
most complicated details, concentrating mainly on the
common practical tasks.
@@ -1020,6 +1022,7 @@ interaction with the Mail Transport Agent.
* Testing Filter Scripts::
* Logging and Debugging::
* Runtime errors::
+* Cautions::
@end menu
@node Start Up
@@ -1082,14 +1085,27 @@ be supplied its own handling procedure. A missing procedure implies
@cindex milter state handler, described
@cindex handler, described
+@cindex connect, handler
+@cindex helo, handler
+@cindex envfrom, handler
+@cindex envrcpt, handler
+@cindex header, handler
+@cindex eoh, handler
+@cindex body, handler
+@cindex eom, handler
+@cindex begin, special handler
+@cindex end, special handler
@anchor{handler names}
A filter script can define up to eight @dfn{milter state handlers},
called after the names of milter states: @samp{connect}, @samp{helo},
@samp{envfrom}, @samp{envrcpt}, @samp{header}, @samp{eoh},
-@samp{body}, and @samp{eom}. The diagram below shows the control flow
-when processing an @acronym{SMTP} transaction. Lines marked with
-@code{C:} show @acronym{SMTP} commands issued by the remote machine
-(the @dfn{client}), those marked with @samp{@result{}} show called handlers
+@samp{body}, and @samp{eom}. Two special handlers are available for
+initialization and cleran-up purposes: @samp{begin} is called before
+the processing starts, and @samp{end} is called after it is finished.
+The diagram below shows the control flow when processing an
+@acronym{SMTP} transaction. Lines marked with @code{C:} show
+@acronym{SMTP} commands issued by the remote machine (the
+@dfn{client}), those marked with @samp{@result{}} show called handlers
with their arguments. An @r{[R]} appearing at the right end of a line
indicates that this part of the transaction can be repeated any number
of times:
@@ -1098,6 +1114,7 @@ of times:
@caption{Mailfromd Control Flow}
@smallexample
@group
+@result{} begin
@result{} connect(@var{hostname}, @var{family}, @var{port}, @samp{IP address})
C: HELO @var{domain}
helo(@var{domain})
@@ -1124,7 +1141,8 @@ do
C: .
@result{} eom
- done
+ done
+@result{} end
@end group
@end smallexample
@end float
@@ -1301,6 +1319,7 @@ names of the formal parameters and the result type, if the function is
to return a meaningful value (function definitions in @acronym{MFL}
are discussed in detail in @pxref{User-defined, User-Defined Functions}).
+@anchor{funcall}
@cindex function calls
A function is invoked using a special construct, @dfn{function
call}:
@@ -1332,7 +1351,7 @@ hostname $client_addr
@noindent
However, such syntax creates several ambiguities, so use it sparingly
if at all. We recommend to always use parentheses when calling a
-function. @FIXME{explain why.}
+function; @xref{Cautions}, for the detailed analysis of of this syntax.
When a function does not deliver a result, it should only be called
as a statement.
@@ -1355,7 +1374,7 @@ designed for a particular task. In order to access a library
function, you must first @dfn{require} a module it is defined in.
This is done using @code{#require} statement. For example, the
function @code{hostname} looks up in the @acronym{DNS} the name
-corresponding to the IP address specified as its argument. This
+corresponding to the @acronym{IP} address specified as its argument. This
function is defined in module @file{dns.mf}, so before calling it you
must require this module:
@@ -1377,9 +1396,9 @@ module on disk and loads it if it is available.
do not have a proper reverse delegation in the Domain Name System.
In the previous section we introduced the library function
@code{hostname}, that looks up in the @acronym{DNS} the name corresponding to
-the IP address specified as its argument. If there is no
+the @acronym{IP} address specified as its argument. If there is no
corresponding name, the function returns its argument unchanged. This
-can be used to test if the IP was resolved, as illustrated in the
+can be used to test if the @acronym{IP} was resolved, as illustrated in the
example below:
@smallexample
@@ -1399,7 +1418,7 @@ done
after which the definition of @code{hostname} becomes available.
An orthogonal function, @code{resolve}, which resolves the symbolic
-name to the corresponding IP address is provided in the same
+name to the corresponding @acronym{IP} address is provided in the same
@file{dns.mf} module.
@node Checking Sender Address
@@ -1486,10 +1505,10 @@ done
@end smallexample
@node SMTP Timeouts
-@section SMTP Timeouts
+@section @acronym{SMTP} Timeouts
When using polling functions, it is important to take into account
-possible delay, which can occur in SMTP transactions. Most often
+possible delay, which can occur in @acronym{SMTP} transactions. Most often
such delays are due to low network bandwidth, but sometimes remote
sites impose them willingly, as a spam-fighting measure@footnote{My
private opinion is that such practice is completely lame.}
@@ -1628,8 +1647,8 @@ done
Another way to avoid infinite looping caused by endless recursive
triggering of @code{on poll}, is to accept relaying of all email originating
-from the local IP cluster with (trusted) clients and SMTP servers,
-provided that the server running mailfromd falls within this IP range:
+from the local @acronym{IP} cluster with (trusted) clients and @acronym{SMTP} servers,
+provided that the server running mailfromd falls within this @acronym{IP} range:
@smallexample
@group
@@ -1654,12 +1673,12 @@ done
@end smallexample
Here, triggering the @code{on poll} statement with more than 1 recursion
-is avoided for all local emails, originating from non-local IPs
-(outside of CIDR range 193.232.0.0/16) - when such an email arrives,
+is avoided for all local emails, originating from non-local @acronym{IP}s
+(outside of @acronym{CIDR} range 193.232.0.0/16) - when such an email arrives,
handler execution falls through to @code{on poll}, which will cause
the server to connect back to itself for local email verification, but
this time, the @code{on poll} check will be skipped, as the server's
-own IP address will be caught by @code{match_cidr} statement.
+own @acronym{IP} address will be caught by @code{match_cidr} statement.
This method has particular advantage over the previous one: it
does not rely on sendmail's relay-domains control, which can be,
alone, too wide for sane relaying control.
@@ -1916,7 +1935,7 @@ interval, which is an integer number. For example, the number
updates the rate record for the given @var{key}, and returns its
value, converted to messages per interval. For example, the following
code limits the mail sending rate for each @samp{email
-address}-@samp{IP} combination to 180 per hour. If the rate value is
+address}-@samp{@acronym{IP}} combination to 180 per hour. If the rate value is
exceeded, the sender is returned a temporary failure response:
@smallexample
@@ -1951,7 +1970,7 @@ intervals are discussed in @ref{time interval specification}.
Greylisting is a simple method of defending against the spam
proposed by Evan Harris. In few words, it consists in recording the
-@samp{sender IP}-@samp{sender email}-@samp{recipient email} triplet of
+@samp{sender @acronym{IP}}-@samp{sender email}-@samp{recipient email} triplet of
mail transactions. Each time the unknown triplet is seen, the
corresponding message is rejected with @code{tempfail} code. If the
mail is legitimate, this will make the originating server will retry
@@ -2020,7 +2039,7 @@ done
@end smallexample
In real life you will have to avoid greylisting some messages, in
-particular those coming from the @samp{<>} address and from the IP
+particular those coming from the @samp{<>} address and from the @acronym{IP}
addresses in your relayed domain. It can easily be done using the
techniques described in previous sections and is left as an exercises
to the reader.
@@ -2196,7 +2215,7 @@ described in the following table:
@table @asis
@item A
- Each field contains the next IP address corresponding to the lookup
+ Each field contains the next @acronym{IP} address corresponding to the lookup
key. Notice, that currently (version @value{VERSION}) there can be at
most one field here, but it may change in the future.
@@ -2913,6 +2932,104 @@ the error and fix it.
calling the @code{stack_trace} function. This can be useful for
debugging, or in your @code{catch} statements.
+@node Cautions
+@section Warnings about some slippery places in @acronym{MFL}
+
+@quotation
+It seemed like a good idea at the time.
+
+--- Brian Kernighan
+@end quotation
+
+ There are some features of @acronym{MFL} which, when used improperly,
+may lead to subtle, hard identifiable errors. These are: concatenation
+operation (@pxref{Concatenation}) and passing arguments to
+one-argument functions without parentheses (@pxref{funcall, Function
+call syntax}).
+
+ Since there is no explicit operator for concatenation, it is often
+necessary to ensure that it happens at the right time by using
+parentheses to enclose the items to concatenate. Consider the
+following example:
+
+@smallexample
+echo toupper "some" "thing"
+@end smallexample
+
+ Should it print @samp{SOMETHING} or just @samp{SOMEthing}? The
+correct answer is the former, but it is difficult to deduce unless you
+are well acquainted with the @acronym{MFL} precedence rules
+(@pxref{Precedence}). Therefore, the rule of thumb is: whenever in
+doubt, parenthesize:
+
+@smallexample
+echo toupper("some" "thing") @result{} "SOMETHING"
+echo toupper("some") "thing" @result{} "SOMEthing"
+@end smallexample
+
+ Quoteless literals (@pxref{Literals}) are yet another dangerous
+feature. Just as the features mentioned above, it stems from the
+good old days when @acronym{MFL} was small and sweet and using
+literals without quotes indeed ``seemed a good idea at the time.'' It
+ceased to seem so after the introduction of user-defined functions,
+though. Consider the following @emph{entire} program text:
+
+@smallexample
+@group
+prog envfrom
+do
+ if hostname($client_addr) = $client_addr
+ reject
+ fi
+done
+@end group
+@end smallexample
+
+ The intent was obviously to reject any mail if it comes from an
+address without a proper @code{PTR} record (@pxref{hostname
+function}). There is a serious error, however: @code{hostname} is not
+a built-in function as it used to be in previous releases@footnote{Up to
+the version 1.3.91.}, and therefore it needs to be defined or required
+prior to using. Otherwise it is no more than a literal, and the whole
+construct @samp{hostname($client_addr)} is regarded by @acronym{MFL}
+compiler as a concatenation of the string @samp{hostname} and the
+value of @samp{client_addr} Sendmail variable. It is easy to see
+using @option{--dump-tree} option:
+
+@smallexample
+$ @kbd{mailfromd --dump-tree test.mf}
+State handlers:
+---------------
+envfrom:
+COND:
+EQ
+ CONCAT:
+ STRING: "hostname"
+ SYMBOL: @{client_addr@}
+ SYMBOL: @{client_addr@}
+IFTRUE
+ reject
+IFFALSE
+@end smallexample
+
+ In effect, the comparison is always false and @code{reject} is never
+called.
+
+ That is why starting from version 3.0 @command{mailfromd} warns
+about any occurrence of an unquoted identifier. In fact, running
+@option{--lint} on the above program, gives:
+
+@smallexample
+$ @kbd{mailfromd --lint test.mf}
+mailfromd: test.mf:3: warning: unquoted identifier `hostname'
+@end smallexample
+
+ Whenever you see such a message, be sure to inspect the source and
+to place quotes around the suspicious string, if it is intended to be
+used as a literal, or to require the corresponding module
+(@pxref{Modules}) (or include the source file directly,
+@pxref{include}), if it is indeed a function name.
+
@node MFL, Mailfromd Configuration, Tutorial, Top
@chapter Mail Filtering Language
@cindex MFL
@@ -2938,7 +3055,8 @@ amount of white-space characters (i.e. spaces, tabulations or newlines).
* Constants::
* Variables::
* Back references::
-* Handlers::
+* Handlers::
+* begin/end::
* Functions:: Functions.
* Expressions:: Expressions.
* Statements::
@@ -3127,7 +3245,7 @@ a true value, and @code{no}, @code{false} or @code{nil} to indicate a
false value.
@item address
- An IP address in ``dotted-quad'' notation or a fully-qualified host
+ An @acronym{IP} address in ``dotted-quad'' notation or a fully-qualified host
name.
@item interval
@@ -3200,7 +3318,7 @@ detailed description.
@deffn {pragma option} initial-response-timeout @var{interval}
@xprindex{initial-response-timeout}
- Sets the time to wait for the initial SMTP response. Default is
+ Sets the time to wait for the initial @acronym{SMTP} response. Default is
@value{INITIAL-RESPONSE-TIMEOUT}. @xref{SMTP Timeouts}, for
the detailed description.
@end deffn
@@ -3358,7 +3476,7 @@ port type is not yet supported.
@deffn {pragma option} milter-timeout @var{interval}
@xprindex{milter-timeout}
Set the timeout value for connection between the filter
-and the MTA. Default value is @value{MILTER-TIMEOUT}. You
+and the @acronym{MTA}. Default value is @value{MILTER-TIMEOUT}. You
normally do not need to change this value.
@end deffn
@@ -4142,7 +4260,7 @@ qualified domain name of the host where @command{mailfromd} is run.
@deftypevar {Predefined Variable} string last_poll_host
Polling functions (@pxref{Polling functions}) set this variable before
-returning. It contains the host name or IP address of the last polled host.
+returning. It contains the host name or @acronym{IP} address of the last polled host.
@end deftypevar
@deftypevar {Predefined Variable} string last_poll_recv
@@ -4292,14 +4410,14 @@ the available handlers and their arguments:
@deffn {Handler} connect (string $1, number $2, number $3, string $4)
@subsubheading Invocation
-This handler is called once at the beginning of each SMTP connection.
+This handler is called once at the beginning of each @acronym{SMTP} connection.
@subsubheading Arguments
@enumerate 1
@item @code{string};
-The host name of the message sender, as reported by MTA. Usually it
+The host name of the message sender, as reported by @acronym{MTA}. Usually it
is determined by a reverse lookup on the host address. If the reverse
-lookup fails, @samp{$1} will contain the message sender's IP address
+lookup fails, @samp{$1} will contain the message sender's @acronym{IP} address
enclosed in square brackets (e.g. @samp{[127.0.0.1]}).
@item @code{number};
@@ -4311,17 +4429,17 @@ definitions for the address families. Supported families are:
@cindex FAMILY_INET
@multitable @columnfractions 0.20 .10 0.70
@headitem Constant @tab Value @tab Meaning
-@item FAMILY_STDIO @tab 0 @tab Standard input/output (the MTA is
+@item FAMILY_STDIO @tab 0 @tab Standard input/output (the @acronym{MTA} is
run with @option{-bs} option)
@item FAMILY_UNIX @tab 1 @tab @acronym{UNIX} socket
-@item FAMILY_INET @tab 2 @tab IPv4 protocol
+@item FAMILY_INET @tab 2 @tab @acronym{IP}v4 protocol
@end multitable
@item @code{number};
Port number if @samp{$2} is @samp{FAMILY_INET}.
@item @code{string};
-Remote IP address if @samp{$2} is @samp{FAMILY_INET} or full file name
+Remote @acronym{IP} address if @samp{$2} is @samp{FAMILY_INET} or full file name
of the socket if @samp{$2} is @samp{FAMILY_UNIX}. If @samp{$2} is
@samp{FAMILY_STDIO}, @samp{$4} is an empty string.
@end enumerate
@@ -4374,9 +4492,9 @@ command, excepting ones listed above, is answered with
2821 (section 3.9), which states:
@quotation
- An SMTP server MUST NOT intentionally close the connection except:
+ An @acronym{SMTP} server @emph{must not} intentionally close the connection except:
@dots{}
- - After detecting the need to shut down the SMTP service and
+ - After detecting the need to shut down the @acronym{SMTP} service and
returning a 421 response code. This response code can be issued
after the server receives any command or, if necessary,
asynchronously from command receipt (on the assumption that the
@@ -4399,8 +4517,8 @@ versions of Sendmail up to 8.14.
@deffn {Handler} helo (string $1)
@subsubheading Invocation
-This handler is called whenever the SMTP client sends @code{HELO} or
-@code{EHLO} command. Depending on the actual MTA configuration, it
+This handler is called whenever the @acronym{SMTP} client sends @code{HELO} or
+@code{EHLO} command. Depending on the actual @acronym{MTA} configuration, it
can be called several times or even not at all.
@subsubheading Arguments
@@ -4410,7 +4528,7 @@ can be called several times or even not at all.
@subsubheading Notes
According to @acronym{RFC} 28221, @code{$1} must be the domain name of the
-sending host, or, in case this is not available, its IP address
+sending host, or, in case this is not available, its @acronym{IP} address
enclosed in square brackets. Be careful when taking decisions based
on this value, because in practice many hosts send arbitrary strings.
We recommend to use @code{heloarg_test} function
@@ -4419,7 +4537,7 @@ We recommend to use @code{heloarg_test} function
@deffn {Handler} envfrom (string $1, string $2)
@subsubheading Invocation
-Called when the SMTP client sends @code{MAIL FROM} command, i.e. once
+Called when the @acronym{SMTP} client sends @code{MAIL FROM} command, i.e. once
at the beginning of each message.
@subsubheading Arguments
@@ -4459,7 +4577,7 @@ an array of arguments.
@deffn {Handler} header (string $1, string $2)
@subsubheading Invocation
-Called once for each header line received after SMTP @code{DATA} command.
+Called once for each header line received after @acronym{SMTP} @code{DATA} command.
@subsubheading Arguments
@enumerate 1
@item @code{string}; Header field name.
@@ -4526,7 +4644,155 @@ For your reference, the following table shows each handler with its arguments:
@end multitable
@end float
+@node begin/end
+@section The @samp{begin} and @samp{end} special handlers
+@cindex begin, special handler
+@cindex end, special handler
+@cindex startup handler
+@cindex handler, startup
+@cindex handler, initialization
+@cindex cleanup handler
+@cindex handler, cleanup
+ Apart from milter handlers defined previously, @acronym{MFL}
+defines two special handlers, called @samp{begin} and @samp{end},
+which supply startup and cleanup instructions for the filter program.
+
+ The @samp{begin} special handler is executed once for each
+@acronym{SMTP} session, after the connection has been established but
+before the first milter handler has been called. Similarly, an
+@samp{end} handler is executed exactly once, after the connection has
+been closed. Neither of handlers takes any arguments.
+
+@kwindex begin
+@kwindex end
+ The two handlers are defined using the following syntax:
+
+@smallexample
+# @r{Begin handler}
+begin
+do
+ @dots{}
+done
+
+# @r{End handler}
+end
+do
+ @dots{}
+done
+@end smallexample
+
+@noindent
+where @samp{@dots{}} represent any @acronym{MFL} statements.
+
+ An @acronym{MFL} program may have multiple @samp{begin} and
+@samp{end} definitions. They can be intermixed with other
+definitions. The compiler combines all @samp{begin}
+statements into a single one, in the order they appear in the
+sources. Similarly, all @samp{end} blocks are concatenated together.
+The resulting @samp{begin} is called once, at the beginning of each
+@acronym{SMTP} session, and @samp{end} is called once at its
+termination.
+
+ Multiple @samp{begin} and @samp{end} handlers are a useful feature
+for writing modules (@pxref{Modules}), because each module can thus
+have its own initialization and cleanup blocks. Notice, however, that
+in this case the order in which subsequent @samp{begin} and @samp{end}
+blocks are executed is not defined. It is only warranted that all
+@samp{begin} blocks are executed at startup and all @samp{end} blocks
+are executed at shutdown. It is also warranted that all @samp{begin}
+and @samp{end} blocks defined within a compilation unit (i.e. a single
+abstract source file, whith all @code{#include} and
+@code{#include_once} statements expanded in place) are executed in
+order of their appearance in the unit.
+
+@cindex @samp{begin}, handler restrictions
+@cindex @samp{end}, handler restrictions
+ Due to their special nature, the startup and cleanup blocks impose
+certain restrictions on the statements that can be used within them:
+
+@enumerate 1
+@cindex @code{return} in @samp{begin}
+@cindex @samp{begin} and @code{return}
+@cindex @code{return} in @samp{end}
+@cindex @samp{end} and @code{return}
+@item @code{return} cannot be used in @samp{begin} and @samp{end}
+handlers. @FIXME{It could be a useful feature, though.}
+
+@cindex @code{accept} in @samp{begin}
+@cindex @samp{begin} and @code{accept}
+@cindex @code{accept} in @samp{end}
+@cindex @samp{end} and @code{accept}
+@cindex @code{continue} in @samp{begin}
+@cindex @samp{begin} and @code{continue}
+@cindex @code{continue} in @samp{end}
+@cindex @samp{end} and @code{continue}
+@cindex @code{discard} in @samp{begin}
+@cindex @samp{begin} and @code{discard}
+@cindex @code{discard} in @samp{end}
+@cindex @samp{end} and @code{discard}
+@cindex @code{reject} in @samp{begin}
+@cindex @samp{begin} and @code{reject}
+@cindex @code{reject} in @samp{end}
+@cindex @samp{end} and @code{reject}
+@cindex @code{tempfail} in @samp{begin}
+@cindex @samp{begin} and @code{tempfail}
+@cindex @code{tempfail} in @samp{end}
+@cindex @samp{end} and @code{tempfail}
+@item The following Sendmail actions cannot be used in them:
+@code{accept}, @code{continue}, @code{discard}, @code{reject},
+@code{tempfail}. They can, however, be used in @code{cache}
+statements, declared in @samp{begin} blocks (see example below).
+
+@cindex @code{add} in @samp{begin}
+@cindex @samp{begin} and @code{add}
+@cindex @code{add} in @samp{end}
+@cindex @samp{end} and @code{add}
+@cindex @code{replace} in @samp{begin}
+@cindex @samp{begin} and @code{replace}
+@cindex @code{replace} in @samp{end}
+@cindex @samp{end} and @code{replace}
+@cindex @code{delete} in @samp{begin}
+@cindex @samp{begin} and @code{delete}
+@cindex @code{delete} in @samp{end}
+@cindex @samp{end} and @code{delete}
+@item Header manipulation actions (@pxref{header manipulation}) can be
+used only in @samp{begin} header.
+@end enumerate
+
+ The @samp{begin} handlers are the usual place to put global
+initialization code to. For example, if you do not want to use
+@acronym{DNS} caching, you can do it this way:
+
+@smallexample
+@group
+begin
+do
+ db_set_active("dns", 0)
+done
+@end group
+@end smallexample
+ Additionally, you can set up global exception handling routines
+there. For example, the following @samp{begin} statement disables
+@acronym{DNS} cache and for all exceptions not handled otherwise
+installs a handler that logs the exception along with the stack trace
+and continues processing the message:
+
+@smallexample
+@group
+begin
+do
+ db_set_active("dns", 0)
+ catch *
+ do
+ echo "Caught exception $1: $2"
+ stack_trace()
+ continue
+ done
+done
+@end group
+@end smallexample
+
@node Functions
@section Functions
@@ -4769,7 +5035,7 @@ strip_domain_part("puszcza.gnu.org.ua", 0) @result{} "gnu.org.ua"
@deftypefn {Library Function} boolean is_ip (string @var{str})
@flindex is_ip.mf
- Returns @samp{true} if @var{str} is a valid IPv4 address. This
+ Returns @samp{true} if @var{str} is a valid @acronym{IP}v4 address. This
function is defined in @file{is_ip.mf} module (@pxref{Modules}).
For example:
@@ -4790,7 +5056,7 @@ is_ip("0.0.0.0") @result{} 1
@deftypefn {Library Function} string revip (string @var{ip})
Reverses octets in @var{ip}, which must be a valid string
-representation of an IPv4 address.
+representation of an @acronym{IP}v4 address.
Example:
@@ -4950,7 +5216,7 @@ variables:
@multitable @columnfractions 0.30 0.70
@headitem Variable @tab Contains
@cindex last_poll_host, global variable, introduced
-@item last_poll_host @tab Host name or IP address of the last polled
+@item last_poll_host @tab Host name or @acronym{IP} address of the last polled
host.
@cindex last_poll_send, global variable, introduced
@item last_poll_send @tab Last @acronym{SMTP} command, sent to this
@@ -4970,7 +5236,7 @@ variables are modified. @xref{cache_used example}, for an example.
@node Internet address manipulation functions
@subsubsection Internet address manipulation functions
- Following functions operate on IPv4 addresses and CIDRs.
+ Following functions operate on @acronym{IP}v4 addresses and @acronym{CIDR}s.
@deftypefn {Built-in Function} number ntohl (number @var{n})
Converts the number @var{n}, from host to network byte order.
@@ -5009,7 +5275,7 @@ negative number:}
inet_aton("255.255.255.255") @result{} -1
@end smallexample
-However, this does not affect arithmetical operations on IP addresses.
+However, this does not affect arithmetical operations on @acronym{IP} addresses.
@end deftypefn
@@ -5023,7 +5289,7 @@ inet_ntoa(2130706433) @result{} "127.0.0.1"
@end deftypefn
@deftypefn {Built-in Function} number len_to_netmask (number @var{n})
-Convert number of masked bits @var{n} to the IPv4 netmask:
+Convert number of masked bits @var{n} to the @acronym{IP}v4 netmask:
@smallexample
inet_ntoa(len_to_netmask(24)) @result{} 255.255.255.0
@@ -5035,7 +5301,7 @@ exception.
@end deftypefn
@deftypefn {Built-in Function} number netmask_to_len (number @var{mask})
-Convert IPv4 netmask @var{mask} into netmask length (number of bits
+Convert @acronym{IP}v4 netmask @var{mask} into netmask length (number of bits
preserved by the mask):
@smallexample
@@ -5052,15 +5318,15 @@ netmask_to_len(inet_aton("254.0.0.0")) @result{} 7
This function is defined in @file{match_cidr.mf}
module (@pxref{Modules}).
- It returns @code{true} if the IP address @var{ip} pertains to the
-IP range @var{cidr}. The first argument, @var{ip}, is a string
-representation of an IP address. The second argument, @var{cidr}, is
-a string representation of a IP range in @acronym{CIDR} notation, i.e.
-@code{"@var{A.B.C.D}/@var{N}"}, where @var{A.B.C.D} is an IPv4
+ It returns @code{true} if the @acronym{IP} address @var{ip} pertains to the
+@acronym{IP} range @var{cidr}. The first argument, @var{ip}, is a string
+representation of an @acronym{IP} address. The second argument, @var{cidr}, is
+a string representation of a @acronym{IP} range in @acronym{CIDR} notation, i.e.
+@code{"@var{A.B.C.D}/@var{N}"}, where @var{A.B.C.D} is an @acronym{IP}v4
address and @var{N} specifies the @dfn{prefix length} -- the number of
shared initial bits, counting from the left side of the address.
- The following example will reject the mail if the IP address of
+ The following example will reject the mail if the @acronym{IP} address of
the sending machine does not belong to the block @code{10.10.1.0/19}:
@smallexample
@@ -5095,7 +5361,7 @@ available after requesting @file{dns.mf} module (@pxref{Modules}):
@end smallexample
@deftypefn {Built-in Function} string dns_getaddr (string @var{domain})
- Returns a whitespace-separated list of IP addresses (@code{A}
+ Returns a whitespace-separated list of @acronym{IP} addresses (@code{A}
records) for @var{domain}. At most 64 addresses are
returned. @FIXME{This limit should be configurable.}
@@ -5104,7 +5370,7 @@ returned. @FIXME{This limit should be configurable.}
@deftypefn {Built-in Function}