mailR(5) mailR(5)
NAME
mailR - language used for mail message header rewriting
DESCRIPTION
The mailR language is used by mail for the rewriting of a mail
message's headers. mailR is used to provide instructions on
how to rewrite headers. It is used in the file
/etc/mail/rewrite or other files (such as /etc/mail/mailsurr)
included from that file.
The mailR language and the file /etc/mail/rewrite are similar
to awk(1). A series of function definitions is given in the
file. These functions include one named main and another
named local, which are executed at various stages of mail
delivery. The main function is executed after a mail message
is read in by mail. The local function is executed before a
mail message is delivered locally.
Additional references may be provided within
/etc/mail/mailsurr file so that further functions (rewrite
instructions) may be executed later.
Statements
A function consists of a sequence of statements. A statement
can be one of the following:
var x Creates a local variable named x. Variable
names start with a letter and consist of
letters, digits or underscores. There are only
local variables, each with a dynamically
assigned type of string, double, header, array
or reference. arrays are associative (can have
any type of index). references are variables
which refer to other variables. Multiple names
may be given, separated by commas. (If a non-
array variable is used in an array context, it
will be converted to an array with the value set
as the 0'th element. If an array is used in a
non-array context, the value of the first
element added to the array will be used.)
var x = expression
Creates a local variable named ``x'' and
initializes it with the value of the expression.
Copyright 1994 Novell, Inc. Page 1
mailR(5) mailR(5)
variable = expression
The value of the variable is replaced with the
value of the expression. If variable is a
reference, the variable referred to is modified
as well.
if (conditional) statement
Tests if the conditional is non-zero or a non-
empty string and executes statement if so. (The
statement is shown on the same line as the if,
but is not required to be so. The same is true
for the following statements as well.)
else statement
This clause is executed if the preceding if
statement is false. The else clause is
optional.
for (expression; conditional; expression) statement
Executes the statement while the conditional is
true.
while (conditional) statement
Executes statement as long as the conditional is
true.
until (conditional) statement
Executes statement as long as the conditional is
false.
break Breaks out of the enclosing for, while or until
loop.
continue Skips the rest of the block in a for, while or
until loop.
123, 12.3, 1.2e3
Numeric constants. The format is defined as an
optional sign, then a string of digits
optionally containing a single decimal point,
then an optional e or E followed by an optional
sign, followed by an integer.
"string" A string constant. As in C, backslash sequences
(\n, \000, \x00) may be embedded within the
string and will be converted to the equivalent
Copyright 1994 Novell, Inc. Page 2
mailR(5) mailR(5)
character.
x[y] A reference to the y'th element of the array x.
x is an associative array. If x[y] does not
already exist, the elements will be created as
needed as an empty string.
operators
x + y numeric addition
x - y numeric subtraction
x * y numeric multiplication
x / y numeric division
x @ y string concatenation
( ) grouping
x < y relational operator
(Note: For relational and equality
operators, if both expressions are
numbers, compare them as numbers,
otherwise compare them as strings.
When numbers are converted to
strings, they are converted as if
the %g printf format had been used.)
x > y relational operator
x <= y relational operator
x >= y relational operator
x == y equality operator
x != y equality operator
x ~ y match, the string in y is
interpreted as a regular expression
pattern. The same regular
expressions permitted in the mail
surrogate file are allowed here.
For example, "xyz" ~ "[ax]" will
Copyright 1994 Novell, Inc. Page 3
mailR(5) mailR(5)
evaluate true.
x !~ y doesn't match, the string in y is
interpreted as a regular expression
pattern. The same regular
expressions permitted in the mail
surrogate file are allowed here.
x && y short circuit logical and
x || y short circuit logical or
!expression Negates the following expression.
# A comment to the end of the line.
{ } Compound statements are surrounded with braces
and may span multiple lines.
; Statements are terminated by semicolons.
function x(var a, reference b, var c)compound-statement
Declares a function named x with the body
compound-statement. The variable declarations
inside of the parentheses declare local
variables of the given names. In this example,
the variables a and c are copies of the values
passed in, while the variable b is a reference
which will modify the original value.
return val Returns a value from a function.
generator x(var a)compound-statement
A generator function is a special type of
function that has a start block. The first call
to a generator must be of the form x(a,b,c)
(with arguments), which will cause the function
to be executed with those arguments, and any
start block within the function will also be
executed. Subsequent calls must be of the form
x() (no arguments) and will skip the start
block. Any local variables declared within the
generator function at the outermost scope will
retain their values between calls to the
generator function. Only var parameters are
permitted; no reference parameters are allowed.
Copyright 1994 Novell, Inc. Page 4
mailR(5) mailR(5)
For example,
for (x = y(a,b,c); x; x = y()) statement
will invoke y() repeatedly until y() returns an
empty string or 0, executing the statement each
time.
start statement
Executes the statement only if this is an
initial invocation of a generator function.
for (x from y) statement
Retrieves all values from the array y, one at a
time, setting x as a reference to the array
element.
for (x in y) statement
Retrieves all values from the array y, one at a
time, setting x each time, as a reference, to
the index of the array element.
include "filename"
The contents of the given filename are inserted
at this point. The include statement is only
allowed outside of function and generator
definitions.
Predefined Functions
A number of functions are predefined. These functions cannot
be redefined.
In those functions that refer to message header names, such as
a To header, the string used to refer to that header may be
given with or without a trailing colon (:) (that is, To: is
also accepted). The search for the header is case
insensitive. The names From and >From refer to the UNIX
Postmark (From_) headers and must not be given with a trailing
colon or in any other case. (Note the trailing space as part
of the name.)
addrparse(var x)
Treats x as a series of RFC-822 addresses separated
by commas and optional newlines. Each RFC-822
address is assumed to be in one of the two forms:
address (comment)
comment <address>
Copyright 1994 Novell, Inc. Page 5
mailR(5) mailR(5)
Returns an array created from x, split on
successive addresses. Each element of the array
comprises another array, whose contents become the
parsed address, split into its constituent
components. For each address, there are the
components address and comment, which include the
corresponding parts of the address. In addition,
there is a component named error, which is set to
an error message if there is any problem in parsing
the address. There are also the components route,
domain_part, and local_part, which are the
corresponding portions of the address when treated
as @route:local-part@domain-part. There is also a
component group_phrase, which is set only if there
is an RFC-822 group list name. All addresses which
are part of the same list have the same group list
name and are found in order. Note that the address
may be empty if there was an error, or if there was
a group list name without any names associated with
it.
append_header(var hdrtag, var afterhdr, var val)
Creates a new header of type hdrtag after the last
header of type afterhdr with value val. If no
header of type afterhdr exists, the header is
created at the end of all other headers. For
example,
append_header("Received", "Received", "by tom")
will create a new Received header after all other
Received headers with the value by tom. The case
used by hdrtag is used for creating the header. A
header also gets created by saying:
headers("Xyz")[0] = string;
If the header Xyz: does not already exist, it will
be created. Otherwise, the first header of that
type will be replaced.
characterset()
Returns the current character set, such as ``US-
ASCII'' or ``ISO-2022-JP''.
delete_header(var hdr)
Deletes all headers of the given name. (The first
>From header cannot be deleted.) Returns 1 if any
Copyright 1994 Novell, Inc. Page 6
mailR(5) mailR(5)
headers were deleted, 0 otherwise.
domain() Returns the domain name of the system.
exists(var hdr)
Returns true if a header of the given type exists,
and false otherwise. For example,
exists("To")
will return true if a To header is in the message.
filter(var command)
If the command is successful, replaces the headers
and message body with the output from the command.
Returns the exit code.
filterbody(var command)
If the command is successful, replaces the message
body with the output from the command. Returns the
exit code.
filterheaders(var command)
If the command is successful, replaces all headers,
except the first "From " header, with the output
from the command. Returns the exit code.
filterstring(var string, var command, reference outstring)
Sends the given string to the given command and
returns the output in outstring. Returns the exit
code. If there are problems with temporary files,
a -2 is returned. If there is a problem executing
the command, a -1 is returned.
fromcrack(var x, reference user, reference date, reference system,
reference forward)
Treats x as a UNIX Postmark header and returns the
parts of the header in the reference variables.
The three forms of UNIX postmarks recognized are
>From user date-string
>From user date-string remote from system
>From user date-string forwarded by user
The system reference is filled in if there is a
``remote from'' system present. The forward
reference is filled in if there is a ``forwarded
Copyright 1994 Novell, Inc. Page 7
mailR(5) mailR(5)
by'' user present. If x is not a valid UNIX
Postmark header, the results are undefined.
fromdate(var seconds)
Returns the date and time formatted as appropriate
for a From UNIX Postmark. The seconds is the time
since January 1, 1970. If 0 is specified, the
current time is used.
getdate(var string)
The string is treated as a date and converted into
seconds since January 1, 1970, which is usable by
the fromdate() and rfc822date() functions. This
requires the use of the DATEMSK environment
variable for the C function getdate(3). If not
set, then the DATEMSK environment variable will
default to point to the file /etc/mail/datemask.
If the date cannot be parsed, a non-positive value
is returned. A 0 value means that getdate returned
a value which could not be converted to a time. A
negative value is the negation of the value
returned in getdate_err when getdate fails. See
the manual page for getdate for further details.
getenv(var x)
Returns the value of the environment variable with
the name x.
gsubstitute(var s1, var regex, var repl)
Return the string created by using the pattern
regex on string s1, making all replacements as
controlled by repl. For example,
gsubstitute("system!user", "(.*)!(.*)", "\\2@\\1")
would return the string iuser@system and
gsubstitute("abcdefg", "[bdf]", "X")
would return the string aXcXeXg.
headers(var string)
Returns array of references to all headers named by
the string, indexed by numbers (starting at 0) and
in the order found in the mail message. For
example,
headers("To")
Copyright 1994 Novell, Inc. Page 8
mailR(5) mailR(5)
would return all To headers. Multiple line headers
are returned as a single string with newlines
embedded. (Leading white space on continuation
lines are preserved.) The reference is live: if
you change a value, it changes for real. If the
given header does not exist, a place holder for one
will be created. (The new header will not become
real until a value has been assigned.)
headers_pattern(var pattern)
Returns array of references to all headers whose
names match the regular expression pattern, indexed
by numbers (starting at 0) and in the order found
in the mail message. For example,
headers_pattern("To")
would return all To headers and
headers_pattern(".*")
would return all headers. Multiple line headers
are returned as a single string with newlines
embedded. (Leading white space on continuation
lines are preserved.) The reference is live: if
you change a value, it changes for real.
int(var x) return value of x truncated to an integer
isbinary() Return 0, 1 or 2 if the message body is text,
generic-text or binary, respectively.
length(var x)
Returns the number of characters in the string x.
lines(var x)
Equivalent to split(x, "\n").
localmessage()
Returns true if the message was created locally.
mailsystem(var x)
If x == 0, return the name of the system, taken
from the cluster name or uname if there is no
cluster name. If x != 0, return the uname of the
system.
Copyright 1994 Novell, Inc. Page 9
mailR(5) mailR(5)
match(var str, var pat, reference length)
Returns the position in string str where the
regular expression pat occurs, 0 if it does not
occur at all, and -1 if the regular expression does
not compile. The length variable is set to the
length of the matched string.
messageid()
Returns a string suitable for use in a Message-ID
or Content-ID header. Each invocation returns a
unique string.
mgetenv(var x)
Returns the value of the mail configuration
variable with the name x.
prepend_header(var x, var beforehdr, var z)
Creates a new header of type x before the first
header of type beforehdr with value z. If no
header of type beforehdr exists, the header is
created before all other headers, but after the
>From UNIX Postmark headers. For example,
prepend_header("Date", "To", rfc822date(0))
will create a new header named Date before the
first To header with the value returned from the
rfc822date() function.
print(var string)
Print the string on standard output.
printheaders()
Print the current headers on standard output.
rand() Returns a random number between 0 and 1.
recipients()
Return an array containing the recipients the mail
message was originally addressed to.
returnpath()
Return a string containing the return path to the
originator of the message.
Copyright 1994 Novell, Inc. Page 10
mailR(5) mailR(5)
rfc822date(var seconds)
Returns the date and time formatted according to
the RFC-822 standard. The seconds is the time
since January 1, 1970. If 0 is specified, the
current time is used.
split(var x, var y)
Returns an array created from x, split on each
occurrence of the string y.
split_pattern(var x, var pat)
Returns an array created from x, split on each
occurrence of the regular expression pattern pat.
srand(var seed)
If the seed is 0, the current time of day is used.
The seed used is returned.
strrstr(var s1, var s2)
Finds the last occurrence of the string s2 in the
string s1, and returns its position (1-n), or 0 if
s2 not present.
strstr(var s1, var s2)
Finds the first occurrence of the string s2 in the
string s1 and returns its position (1-n), or 0 if
s2 is not present.
substitute(var s1, var regex, var repl)
Returns the string created by using the pattern
regex on string s1, making the first replacement as
controlled by repl. For example,
substitute("system!user", "(.*)!(.*)", "\\2@\\1")
would return the string user@system, and
substitute("abcdefg", "[bdf]", "X")
would return the string aXcdefg.
substr(var s, var m, var n)
Returns the n-character substring of s that begins
at position m (1-based).
sysname() If there is a domain name, then sysname() is
equivalent to mailsystem(0).domain(). Otherwise,
it is equivalent to mailsystem(0).
Copyright 1994 Novell, Inc. Page 11
mailR(5) mailR(5)
texttype() Returns the strings text, generic-text or binary
depending on whether the message contains strictly
7-bit text, 8-bit text or binary contents.
time() Returns the current time as a number of seconds
since Jan. 1, 1970.
username() Returns the name of the user executing this
command.
Attributes
Some variable types have attributes. An attribute is referred
to using x.attribute.
header variables: .name
Return the name of a header, "" if the variable not a
header variable. For example,
headers("To")[0].name
will return the string, To:.
array values: .count
Return the number of elements in the array, 0 if
there are no elements or the variable is not an
array.
EXAMPLES
Numerous mailR examples may be found in the file
/etc/mail/rewrite.samp.
# this function is performed for all messages
function main()
{
# if we're a message generated locally
if (localmessage())
{
# make certain that we have a Date: header
if (!exists("Date"))
headers("Date")[0] = rfc822date(0);
# make certain that the Date: header has the proper format
else
headers("Date")[0] = rfc822date(getdate(headers("Date")[0]));
# if there isn't a From: header, create one
if (!exists("From"))
headers("From")[0] = username() @ "@" @ sysname();
Copyright 1994 Novell, Inc. Page 12
mailR(5) mailR(5)
}
# collapse multiple >From_ headers into a single >From_ header
collapse_from_lines();
# convert AT&T Mail MTA messages into MIME format
if (exists("message-version") && exists("end-of-protocol"))
filter("mtatomime");
# if not a MIME message, convert to MIME
if (!exists("mime-version"))
{
headers("Mime-Version")[0] = "1.0";
# convert to base64-encoded binary
if (texttype() == "binary")
{
filterbody("mimencode -b -p");
headers("Content-Type")[0] = "application/octet-stream";
headers("Content-Encoding")[0] = "base-64";
}
# convert to quoted-printable-encoded 8-bit text
else if (texttype() == "generic-text")
{
filterbody("mimencode -q");
headers("Content-Type")[0] = "text/plain; charset=" @
characterset();
headers("Content-Encoding")[0] = "quoted-printable";
}
# regular text, mark it as such
else
headers("Content-Type")[0] = "text/plain";
}
}
function collapse_from_lines()
{
# loop over existing >From headers, extracting
# user and system from each
var user, date, system, forward, save_system, save_user,
save_date, hdr;
for (hdr from headers(">From"))
{
fromcrack(hdr, user, date, system, forward);
Copyright 1994 Novell, Inc. Page 13
mailR(5) mailR(5)
if (!forward)
{
save_user = user;
save_date = date;
if (save_system)
save_system = save_system @ "!" @ system;
else
save_system = system;
}
}
delete_header(">From");
if (save_system)
headers("From")[0] = save_user @ " " @ save_date @
" remote from " @ save_system;
else
headers("From")[0] = save_user @ " " @ save_date;
}
REFERENCES
mail(1), mailsurr(4), rewrite(4)
Copyright 1994 Novell, Inc. Page 14