|
Mailfromd |
General-Purpose Mail Filter |
Sergey Poznyakoff |
| Mailfromd Manual (split by node): | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
? |
Complicated filter scripts can often be simplified and made more manageable by defining new functions.
The function definitions can appear anywhere between the handler declarations in a filter program. The only requirement is that the function definition occurs before the place where the function is invoked.
The definition of a function named name looks like this:
[qualifier] func name (param-decl) returns data-type do function-body done |
name is the name of the function to define, param-decl is a comma-separated list of parameter declarations. The syntax of the latter is the same as that of variable declarations (see section Variable declarations), i.e.:
type name |
declares the parameter name having the type type. The
type is string or number.
Optional qualifier declares the scope of visibility for that function (see section Scope of Visibility). It is similar to that of variables, except that functions cannot be local (i.e. you cannot declare function within another function).
The public qualifier declares a function that may be referred
to from any module, whereas the static qualifier declares a
function that may be called only from the current module
(see section Modules). The default scope is ‘public’,
unless specified otherwise in the module declaration (see section Declaring Modules).
For example, the following declares a function ‘sum’, that takes two numeric arguments and returns a numeric value:
func sum(number x, number y) returns number |
Similarly, the following is a declaration of a static function:
static func sum(number x, number y) returns number |
Parameters are referenced in the function-body by their name,
using the syntax for variable references: %name. The
value of a parameter can be altered using set statement, the
same way as for variables.
A function can be declared to take a certain number of optional
arguments. In function declaration, optional abstract arguments
must be placed after the mandatory ones, and must be separated from
them with a semicolon. The following example is a definition of
function foo, which takes two mandatory and two optional
arguments:
func foo(string msg, string email; number x, string pfx) |
Mandatory arguments are: msg and email. Optional
arguments are: x and pfx. The actual number of
parameters supplied to the function is returned by a special construct
$#. In addition, the special construct @arg
evaluates to the ordinal number of variable arg in the list of
formal parameters (the first argument has number ‘0’). These two
constructs can be used to verify whether an argument is supplied to
the function.
The actual parameter for argument n is supplied if the number
of actual parameters ($#) is greater than its ordinal number
in the declaration list (@n). So, to check if an
optional argument arg is supplied, the following condition can
be used:
func foo(string msg, string email; number x, string arg)
do
if $# > @arg
…
fi
|
The default mailfromd installation provides a special
macro for this purpose: see defined. Using it, the example above
could be rewritten as:
func foo(string msg, string email; number x, string arg)
do
if defined(arg)
…
fi
|
Within a function body, optional arguments are referenced exactly the same way as the mandatory ones. Attempt to dereference an optional argument for which no actual parameter was supplied, results in an undefined value, so be sure to check whether a parameter is passed before dereferencing it.
A function can also take variable number of arguments (such
functions are called variadic). This is
indicated by the use of ellipsis as the last abstract argument. The
statement below defines a function foo taking one mandatory, one
optional and any number of additional arguments:
func foo (string a ; string b, ...) |
All actual arguments passed in a list of variable arguments are coerced to string data type. To refer to these arguments in the function body, the following construct is used:
$(expr) |
where expr is any valid MFL expression, evaluating to
a number n. This construct refers to the value of nth
actual parameter from the variable argument list. Parameters are
numbered from ‘1’, so the first variable parameter is $(1),
and the last one is $($# - Nm - No), where Nm
and No are numbers of mandatory and optional arguments to the
function.
For example, the function below prints all its arguments:
func pargs (string text, ...)
do
echo "text=%text"
loop for number i 1,
while %i <= $# - 1,
set i %i + 1
do
echo "arg %i=" . $(%i)
done
done
|
Note the loop limits. The last variable argument has number $#
- 1, because the function takes one mandatory argument.
The function-body is any list of valid mailfromd
statements. In addition to the statements discussed below
(see section Statements) it can also contain the return statement,
which is used to return a value from the function. The syntax of the
return statement is
return value |
As an example of this, consider the following code snippet that defines the function ‘sum’ to return a sum of its two arguments:
func sum(number x, number y) returns number
do
return %x + %y
done
|
The returns part in the function declaration is optional. A
declaration lacking it defines a procedure, or void
function, i.e. a function that is not supposed to return any value.
Such functions cannot be used in expressions, instead they are
used as statements (see section Statements). The following example
shows a function that emits a customized temporary failure notice:
func stdtf() do tempfail 451 4.3.5 "Try again later" done |
A function may have several names. An alternative name (or
alias) can be assigned to a function by using alias
keyword, placed after param-decl part, for example:
func foo() alias bar returns string do … done |
After this declaration, both foo() and bar() will refer
to the same function.
The number of function aliases is unlimited. The following fragment declares a function having three names:
func foo() alias bar alias baz returns string do … done |
Although this feature is rarely needed, there are sometimes cases when it may be necessary.
A variable declared within a function becomes a local variable to
this function. Its lexical scope ends with the terminating
done statement.
Parameters, local variables and global variables are using separate namespaces, so a parameter name can coincide with the name of a global, in which case a parameter is said to shadow the global. All references to its name will refer to the parameter, until the end of its scope is reached, where the global one becomes visible again. Consider the following example:
number x
func foo(string x)
do
echo "foo: %x"
done
prog envfrom
do
set x "Global"
foo("Local")
echo %x
done
|
Running mailfromd --test with this configuration will
display:
|
| Mailfromd Manual (split by node): | ![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
? |
Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.