Apart from the milter handlers described in the previous section, MFL provides several special handlers, that serve as hooks, allowing the programmer to insert code in certain important points of the control flow.
Syntactically, special handlers are similar to milter state handlers, i.e. they are defined as:
prog handler do ... done
(handler being the handler name).
Special handlers can be subdivided into three groups.
The first group are begin
and end
handlers. These
are run at the beginning and before the end of each SMTP session and
are used to provide a session-specific initialization and cleanup
routines.
The second group are startup
and shutdown
handlers,
which provide global initialization and cleanup routines. These
handlers are invoked exactly once: startup
when
mailfromd
has started up, but hasn’t yet begun to serve
milter requests, and shutdown
when mailfromd
is about
to terminate.
Finally, the action
handler is run before executing each
reply action (see reply actions).
• begin/end | Session ‘begin’ and ‘end’ special handlers. | |
• startup/shutdown | Global startup and shutdown handlers. | |
• action hook | Action hook handler. |
Next: startup/shutdown, Up: Special handlers [Contents][Index]
These two special handlers are executed once for each session, marking its beginning and end. Neither of them takes any arguments:
# Begin handler
prog begin
do
…
done
The begin
handler is run once for each SMTP session,
after the connection has been established but before the first milter
handler has been called.
# End handler
prog end
do
…
done
The end
handler is run once for each SMTP session,
after all other handlers have finished their work and
mailfromd
has already returned the resulting status to the
MTA and closed connection.
Multiple ‘begin’ and ‘end’ handlers are a useful feature
for writing modules (see Modules), because each module can thus
have its own initialization and cleanup blocks. Notice, however, that
in this case the order in which subsequent ‘begin’ and ‘end’
blocks are executed is not defined. It is only warranted that all
‘begin’ blocks are executed at startup and all ‘end’ blocks
are executed at shutdown. It is also warranted that all ‘begin’
and ‘end’ blocks defined within a compilation unit (i.e. a single
abstract source file, with all #include
and
#include_once
statements expanded in place) are executed in
order of their appearance in the unit.
Due to their special nature, the startup and cleanup blocks impose certain restrictions on the statements that can be used within them:
return
cannot be used in ‘begin’ and ‘end’
handlers.
accept
, continue
, discard
, reject
,
tempfail
. They can, however, be used in catch
statements, declared in ‘begin’ blocks (see example below).
The ‘begin’ handlers are the usual place to put global initialization code to. For example, if you do not want to use DNS caching, you can do it this way:
prog begin do db_set_active("dns", 0) done
Additionally, you can set up global exception handling routines there. For example, the following ‘begin’ statement installs a handler for all exceptions not handled otherwise that logs the exception along with the stack trace and continues processing the message:
prog begin do catch * do echo "Caught exception $1: $2" stack_trace() continue done done
Next: action hook, Previous: begin/end, Up: Special handlers [Contents][Index]
Yet another pair of special handlers, startup
and
shutdown
, can be used for global initialization and cleanup.
The startup
handler is called exactly once, as a part of
mailfromd
startup session.
This handler is normally used in mfmod interface modules to load the shared library part (see mfmod).
This handler is called during the normal program shutdown sequence, before exiting.
Both handlers bear certain similarity to begin
and end
:
they take no arguments, and their use is subject to the same
restrictions (see begin/end restrictions). Additionally,
the following features cannot be used in global handlers:
Previous: startup/shutdown, Up: Special handlers [Contents][Index]
Action hook handler is run implicitly before executing each reply
action, such as accept
, reject
, etc. See reply actions, for a discussion of reply action statements.
Upon invocation, the handler is passed four arguments:
status
module defines the following symbolic names for action identifiers:
ACCEPT_ACTION
CONTINUE_ACTION
DISCARD_ACTION
REJECT_ACTION
TEMPFAIL_ACTION
To convert these to textual action names, use the
milter_action_name
function (see milter_action_name).
The last three arguments are meaningful only for reject
and
tempfail
actions. For the remaining three actions
(accept
, discard
, and continue
), empty strings
are passed.
The action hook handler is useful mainly for logging and accounting
purposes. For example, the code fragment below assumes that the
openmetrics
module is used (see mfmod_openmetrics in mfmod_openmetrics reference).
It increases the corresponding metrics before taking the action.
Additionally, for reject
and tempfail
actions, the
metrics ‘reject_code’ and ‘tempfail_code’ are
increased, where code is the three-digit SMTP status code being
sent to the server.
prog action do openmetrics_incr(milter_action_name($1)) switch $1 do case REJECT_ACTION: openmetrics_incr("reject_" . $2) case TEMPFAIL_ACTION: openmetrics_incr("tempfail_" . $2) done done
Previous: startup/shutdown, Up: Special handlers [Contents][Index]