Previous: User-defined Exceptions, Up: Exceptional Conditions [Contents][Index]
Normally when an exception is signalled, the program execution is
terminated and the MTA is returned a tempfail
status. Additional information regarding the exception is then output
to the logging channel (see Logging and Debugging). However, the
user can intercept any exception by installing his own
exception-handling routines.
An exception-handling routine is introduced by a try–catch statement, which has the following syntax:
try do stmtlist done catch exception-list do handler-body done
where stmtlist and handler-body are sequences of
MFL statements and exception-list is the list of
exception types, separated by the word or. A special
exception-list ‘*’ is allowed and means all exceptions.
This construct works as follows. First, the statements from stmtlist are executed. If the execution finishes successfully, control is passed to the first statement after the ‘catch’ block. Otherwise, if an exception is signalled and this exception is listed in exception-list, the execution is passed to the handler-body. If the exception is not listed in exception-list, it is handled as usual.
The following example shows a ‘try--catch’ construct used for
handling eventual exceptions, signalled by primitive_hasmx.
try
do
if primitive_hasmx(domainpart($f))
accept
else
reject
fi
done
catch e_failure or e_temp_failure
do
echo "primitive_hasmx failed"
continue
done
The ‘try--catch’ statement can appear anywhere inside a function or a handler, but it cannot appear outside of them. It can also be nested within another ‘try--catch’, in either of its parts. Upon exit from a function or milter handler, all exceptions are restored to the state they had when it has been entered.
A catch block can also be used alone, without preceding try
part. Such a construct is called a standalone catch. It is
mostly useful for setting global exception handlers in a begin
statement (see The ‘begin’ and ‘end’ special handlers). When used within a usual function or
handler, the exception handlers set by a standalone catch
remain in force until either another standalone catch appears further
in the same function or handler, or an end of the function is
encountered, whichever occurs first.
A standalone catch defined within a function must return from
it by executing return statement. If it does not do that
explicitly, the default value of 1 is returned. A standalone catch
defined within a milter handler must end execution with any of the
following actions: accept, continue, discard,
reject, tempfail. By default, continue is
used.
It is not recommended to mix ‘try--catch’ constructs and standalone catches. If a standalone catch appears within a ‘try--catch’ statement, its scope of visibility is undefined.
Upon entry to a handler-body, two implicit positional arguments
are defined, which can be referenced in handler-body as $1
and $217. The first argument gives the
numeric code of the exception that has occurred. The second argument
is a textual string containing a human-readable description of the exception.
The following is an improved version of the previous example, which uses these parameters to supply more information about the failure:
try
do
if primitive_hasmx(domainpart($f))
accept
else
reject
fi
done
catch e_failure or e_temp_failure
do
echo "Caught exception $1: $2"
continue
done
The following example defines the function hasmx that
returns true if the domain part of its argument has any ‘MX’ records, and
false if it does not or if an exception occurs 18.
func hasmx (string s)
returns number
do
try
do
return primitive_hasmx(domainpart(s))
done
catch *
do
return 0
done
done
The same function can written using standalone catch:
func hasmx (string s)
returns number
do
catch *
do
return 0
done
return primitive_hasmx(domainpart(s))
done
All variables remain visible within catch body, with the
exception of positional arguments of the enclosing handler. To access
positional arguments of a handler from the catch body, assign
them to local variables prior to the ‘try--catch’ construct, e.g.:
prog header
do
string hname $1
string hvalue $2
try
do
…
done
catch *
do
echo "Exception $1 while processing header %hname: %hvalue"
echo $2
tempfail
done
You can also generate (or raise) exceptions explicitly in the
code, using throw statement:
throw excode descr
The arguments correspond exactly to the positional parameters of the
catch statement: excode gives the numeric code of the
exception, descr gives its textual description. This statement
can be used in complex scripts to create non-local exits from deeply
nested statements.
Notice, that the the excode argument must be an immediate
value: an exception identifier (either a built-in one or one declared
previously using a dclex statement).
As of mailfromd version
9.2, there is also a third implicit argument, which holds
the value of program counter where the exception occurred. Currently
it is considered to be an implementation artifact. Filter writers are
discouraged from relying on it.
This function is
part of the mailfromd library, See hasmx.
Previous: User-defined Exceptions, Up: Exceptional Conditions [Contents][Index]