Next: , Previous: , Up: MFL   [Contents][Index]

4.15 Initialization and Cleanup Handlers

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).


Next: , Up: Special handlers   [Contents][Index]

4.15.1 The ‘begin’ and ‘end’ special handlers

These two special handlers are executed once for each session, marking its beginning and end. Neither of them takes any arguments:

Handler: begin
# 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.

Handler: end
# 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:

  1. return cannot be used in ‘begin’ and ‘end’ handlers.
  2. The following Sendmail actions cannot be used in them: accept, continue, discard, reject, tempfail. They can, however, be used in catch statements, declared in ‘begin’ blocks (see example below).
  3. Header manipulation actions (see header manipulation) cannot be used in ‘end’ handler.

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: , Previous: , Up: Special handlers   [Contents][Index]

4.15.2 Global startup and shutdown handlers.

Yet another pair of special handlers, startup and shutdown, can be used for global initialization and cleanup.

Handler: startup

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).

Handler: shutdown

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:

  1. Sendmail macros.
  2. Message modification functions.

Previous: , Up: Special handlers   [Contents][Index]

4.15.3 Action Hook

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:

  1. Identifier of the action which is about to be performed. Each action is assigned a numeric identifier. The 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).

  2. SMTP code of the reply
  3. Extended reply code
  4. Textual message passed to the action.

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: , Up: Special handlers   [Contents][Index]