<!doctype linuxdoc system>

<article opts="titlepage">

<titlepag>
<title>ZMailer Manual
<author>this space is for author information
<date>v1.5, 21 October 1997
</titlepag>

<toc>


<!-- tutorial.sgml -->
<sect>Tutorial
<p>

<sect1>Introduction to Email
<p>
<sect2>Messaging
<p>
This chapter is quite different from the rest of this document.
Here we build a foundation for understanding messaging, instead
of focusing on how ZMailer behaves.
<p>
This chapter may feel a bit theoretical and abstract, being detached
from practical life.
<p>
In reality, however, experience shows that most problems with messaging
are a result of not understanding the underlying messaging model, or of
not respecting said model.
<p>
The terminology used here may seem a bit X.400 oriented.
It is, because folks from what was then known as CCITT (now known as ITU-T)
adapted the model originally developed by IFIP.
Of course, CCITT added a lot of things of its own invention (like
ADMDs and PRMDs), that we don't need to bother ourselves with.
<p>
Although the terminology comes from X.400, it is in no way restricted to it.
Our presentation here is a generic messaging presentation not restricted
to any type of protocol.
<p>
Messaging, as the name says, is all about exchanging messages,
short (or sometimes long) pieces of information.
Messaging is always directional (which means that there is always
a sender and one or more recipients), targeted (the list of recipients
is fixed) and store-and-forward based.
<p>
There are a few messaging-like applications in which the message is
broadcast to a wide, unspecified audience.
A prime example of this latter application is Usenet News.
News is not messaging, as it is not targeted.
<p>
So what about mailing lists that are linked to News, are they messaging or not?
As long as the message is transported as a mail message, it is messaging.
One of the recipients of the message may well be a Usenet News newsgroup.
Similarly, a sender of a message might be the News system, or the author
who initiated the submission by using News. Messaging is not necessarily
interpersonal.
<p>
It is also quite normal for different applications to communicate by using
messaging methods.
A prime example of this would be EDI traffic. It is clearly messaging,
but not interpersonal.

<sect3>The Messaging Model
<p>
In addition to users, the basic building blocks of messaging are
<bf>User Agents (UAs)</bf> and <bf>Message Transfer Agents (MTAs)</bf>.
User agents are the interface through which a human user interacts with
the messaging system.
On non-interpersonal messaging user agents may be built directly into
applications.
MTAs are used to transport messages from one computer system to another.
An example of a good MTA is ZMailer. 
<bf>Access Units (AUs)</bf> can be used for accessing telematic services,
for example telefax. 
<bf>Message Stores (MSs)</bf> can be used between MTAs and UAs.
They are used for storing messages before and while UAs are used
to access and manipulate them.
<bf>Gateways (GWs)</bf> are used in between two different types
of messaging systems, for example between SMTP and X.400 mail.
Gateways are conceptually made of two MTAs and a UA that interconnects them.

There are two more acronyms worth looking at in the messaging model,
namely <bf>MTS (Message Transport System)</bf> and
<bf>MHS (Message Handling System)</bf>.
MTS is the collection of MTAs (and GWs),
while MHS includes MTS and UA functionality (UAs, MSs and AUs).

<bf>This area will be modified!!!</bf>


A graphical example of the messaging model is shown in figure 
<ref id="msg_modl">, page <pageref id="msg_modl">. It 
shows the relationships between different elements of the model.

<figure>
    <eps file="msg_modl">
    <caption><label id="msg_modl">A graphical example of the messaging model.
</figure>




As can be seen, a user may use more than one UA, and a UA can be connected 
to more than one MTA.

Although it is important to understand the relationships between different 
entities in the messaging model, it is even more important to understand the 
nature of a message and the way UAs and MTAs deal with it.

A message consists of a body and headers. In case of messages with more 
than one bodypart (for example some MIME messages) the different body 
parts are all part of the outermost bodypart.

Normally a message looks roughly like this:
<tscreen><verb>
Headers
	From:	The Manager
	To:	One Bright Employee
	CC:	secretary
	Subject:Salary raise
	Date:	17 May 1997

Body
	Dear Employee,
	...
	The Manager
</verb></tscreen>

In a more complex case the structure of a message might be something like this:
<tscreen><verb>
Headers
Body
	Headers
	Body
		Headers
		Body
		Headers
		Body
	Headers
	Body
</verb></tscreen>

As can be seen, there is always just one outermost body that contains 
all other bodyparts. In some cases, for example X.400 the protocol 
seems to violate this by leaving out the outermost bodypart. However, 
even on those cases we must assume, at the abstract level, 
that the outermost bodypart is there.

However, this is not all that there is to the structure of a message. 
When a message is in transit, being handled by MTAs it is put inside 
an envelope, just like a normal letter is inside an envelope while 
the postal service is carrying it. Just like the postal service is not 
permitted to look inside the envelope, neither are MTAs permitted 
to look inside. Whenever there is a need to look inside the envelope, 
it is always a UA function, and done on behalf, and on the authority of, a UA.

There are some violations of this. When using the SMTP protocol, the 
<tt>Received:</tt> lines are put in the headers by MTAs. This is bad 
engineering, but as the process of adding a new header line is fairly 
straightforward, it doesn't cause too much pain. In some cases MTAs 
modify the header even more, and sometimes they even mess with the body. 
This is a sure recipe for trouble.


Graphically, the way a message should be dealt with is shown 
in figure <ref id="msg_rout">, page <pageref id="msg_rout">.

<figure>
        <eps file="msg_rout">
        <caption><label id="msg_rout">How a message should be handled. 
</figure>




The user creates the message with the help of a UA. How the interaction 
is arranged is a local matter. Once the message has been prepared, 
it is passed to a nearby MTA together with necessary envelope 
information and put into an envelope. The MTA puts its stamp on 
the envelope to show that it has received the message. The first 
MTA passes the message to the second MTA. The second MTA puts its 
stamp to the message and passes it to the third MTA, and so on. 
The final MTA passes the message to a UA, and the envelope is removed.

There are at least three ways to pass the message from an MTA to a UA. 
The message may be pushed to a (running) UA, a UA may pull it from an MTA, 
or an MTA may pass the message to an MS from which a UA will receive it at 
a convenient time.

The normal UNIX way of delivering mail (<tt>/usr/spool/mail/user</tt>) can be 
seen as any of the above three mechanisms, but should normally be seen as a 
UA pulling a message. The reason for this confusion is with the de-facto SMTP 
standard MTA, Sendmail. Although Sendmail is in many ways a very clever 
piece of software, it is also the reason for many problems, as it has 
blurred the line between MTA and UA. Sendmail is clearly an MTA, but 
it also performs many of the UA level functions, like handling of 
<tt>.forward</tt> files. This behaviour has become the de-facto standard 
way for UNIX MTAs to behave, making it necessary for any MTA, including ZMailer, 
to behave the same way.

<sect3>Routing And Delivering Messages
<p>

As MTAs only deal with envelopes, all routing and delivery decisions have to be 
based on information available on the envelope. It follows from this that 
the envelope and headers may contain conflicting information. This is normal, 
and is not a cause for worry.

MTAs may, and often do modify addresses present in the envelope. This might 
include changing addresses to a format more suitable for mail delivery and 
alias expansion.

It is important to make a distinction between aliasing and forwarding mail. 
Aliasing is an MTA function, in which an MTA effectively knows that to reach 
a seemingly local user, mail should be sent to a different address. 
To accomplish this, the MTA changes the recipient information on the envelope. 
Forwarding is a UA function. When forwarding, the mail message is received 
by the original, intended recipient, and re-sent to another address. Although 
forwarding is a UA function, it doesn't have to result in a change to body or 
headers, but on the envelope, both sender and recipient should be changed. 
Sendmail bluntly violates this, and makes most other MTAs violate it as well.

Most mailing lists today are just alias expansions, on which one recipient 
address on the envelope is replaced with multiple addresses. In many cases 
this is a reasonable approach. However, all major mailing lists should be 
set up as a UA function. This involves changing not only the recipient 
address but also the sender address in the envelope. In this way, 
undeliverable messages are sent to the owner of the list, who can deal 
with the problem, and not to the sender of the message, who can do nothing 
to remedy the situation.

Error messages must be sent to the envelope sender address, as this is a 
MTA function. If a header like <tt>Errors-to:</tt> is being used, it implies 
that envelope sender should be sent to the one in the <tt>Errors-to:</tt> header.

Replies to messages should be sent to header addresses, because replying is 
a UA function.

<sect1>ZMailer's Features and Facilities
<p>
<sect2>Introduction
<p>
ZMailer is a mailer subsystem for the UNIX operating system.  A mailer is in
charge of handling all mail messages that are created on a system
(typically a single host), from their creation until final disposition
locally or by transfer to another system. As such, the mailer subsystem
(the Message Transfer Agent) must interface to local mail reading and
composing programs (User Agents), to the various transport methods that can
be used to reach other mailers, and to a variety of databases describing
the mailer's environment. ZMailer provides this functionality in a package
and with a philosophy that has benefited from experiences with earlier
mailers. ZMailer provides a capable, robust, efficient subsystem to do the
job, which will excel in demanding environments, but is simple enough to
fit easily everywhere.

<sect2>Design Summary
<p>
ZMailer is a multi-process mailer, using two daemon processes to manipulate
messages.  One of these processes is a router, and makes all decisions
about what should happen to a message.  The other daemon is a message queue
manager, used to schedule delivery of messages.  The Router uses a
configuration file that closely follows Bourne shell script syntax and
semantics, with minimal magic.  Message files are moved around in a series
of directories, and the Scheduler and its Transport Agents run off of
control files created by the Router.

The Router will process messages one at a time, as it finds them in a
directory where User Agents submit their outgoing messages.  Envelope and
Message Header information is all kept in the same message file along with
the message body, and this file is never modified by any ZMailer program.
After parsing the envelope and RFC822 header information, the Router
validates the information extracted, and calls functions defined in the
configuration file to decide exactly how to deliver the message and how to
transform the embedded addresses.  The algorithms that do this are easily
reconfigurable, since the control flow and address manipulation is
specified by familiar shell script statements.  When the Router is
finished, it will produce a message control file for use by the delivery
processing stage of ZMailer, and move the original message file to another
location.

Once the Router has decided what to do with each of the addresses in a
message, the Scheduler builds a summary of this information by reading the
control file created by the Router.  This knowledge is merged with a data
structure it maintains that stores which messages are supposed to be sent
where, and how.  According to a pre-arranged agenda, the Scheduler will
execute delivery programs to properly move the message envelope, header,
and body, to the immediate destination.  These delivery programs are called
Transport Agents, and communicate with the Scheduler using a simple
protocol that tells them which messages to process and returns status
reports to the Scheduler.  The Scheduler also manages status reports,
taking appropriate action on delivery errors and when all delivery
instructions for a message have been processed.

There are several standard Transport Agents included with the ZMailer
distribution.  The collection currently includes a local delivery program,
an SMTP client implementation, and a Transport Agent that can run
Sendmail-compatible delivery programs.

A separate utility allows querying the Scheduler for the state of its mail
queues.  For existing Sendmail installations, a replacement program is
included that simulates most of the Sendmail functionality in the ZMailer
environment.  This allows ZMailer to replace a Sendmail installation
without requiring changes in standard User Agents.

<sect1>Running ZMailer
<p>
ZMailer is fairly simple to run, once the setups are completed
it can be left to run on its own with very little supervision.

Things that might need supervision are things like:
<itemize>
<item>Timely cycling of log files, which otherwise will grow until
they fill all of the available disk space  (One need not log
everything possible, about the only thing this system does not
allow you to log is the message body content.)
<item>Keeping watchful eye on  <tt>&dollar;POSTOFFICE/freezer/</tt>, and 
<tt>&dollar;POSTOFFICE/postman/</tt>
directories.  Former for processing SPAM email, latter for
pathological problem cases.  (More at  3.3.4)
</itemize>
We look closer into these issues at latter parts of this document,
but now it is sufficient to tell, that the principal tool for active
monitoring of the system health is command:
<tscreen><verb>
mailq -ss
</verb></tscreen>
which does tell, if router, or scheduler are up and about, or not,
and also does tell about the sizes of the different sub-spools.

The general management interface for starting and stopping different
subsystems is command
<tscreen><verb>
zmailer
</verb></tscreen>
which the system installs into <tt>&dollar;MAILBIN/</tt> directory, and which command usually needs a symlink to itself from some more common location for
administrative convenience
( <tt>/usr/sbin/zmailer --> &dollar;MAILBIN/zmailer</tt> )
so that the administrator does not need to add  <tt>&dollar;MAILBIN/</tt>  directory
into his or her <tt>PATH</tt>.   On overall, it is intention that not even 
admin
user should need to run directly the programs at the <tt>&dollar;MAILBIN/</tt> directory.

Basically the administration is as follows:
<itemize>
<item>At system startup (to start all subsystems):
<tscreen><verb>
zmailer
</verb></tscreen>
<item>At system shutdown (to kill all subsystems):
<tscreen><verb>
zmailer kill
</verb></tscreen>
</itemize>
There is also a way to make sure the system will not let the ZMailer
to start at the system startup, because you have some massive work
going on, and the system is not in condition to accept email for a while: 
<tscreen><verb>
zmailer freeze
</verb></tscreen>
and the antidote for the ``freeze'' is, naturally:
<tscreen><verb>
zmailer thaw
</verb></tscreen>
Normal operations can not be started at ``frozen'' system without ``thawing'' it at first.

The user-visible component of the ZMailer is (for de-facto interface)
<tscreen><verb>
/usr/lib/sendmail
</verb></tscreen>
(a.k.a.) <tt>/usr/sbin/sendmail</tt>
which is ``simple'' message submission program that mimics sendmail
commands behaviour, but of course many details of sendmail are
not really implemented at all, mostly because they do not have
equivalents in the ZMailer system.

There are also functional equivalents (or near equivalents) of
other sendmail/system utilities:  <em>mailq</em>, <em>newaliases</em>, <em>vacation</em>

<sect1>Comparison With Other Popular MTA's
<p>
<bf>Sendmail</bf>, in the right hands, can be quite a flexible tool to translate
between the different conventions of various networks.  Unfortunately this
is accomplished by programming in an unfamiliar production language
containing many magic features.  The learning time for doing this is very
long, the effort involved is that of learning a completely new language and
environment. Moreover, Sendmail has all major components built into a
single large program. Both of these design decisions have been acknowledged
as mistakes by the author of Sendmail.  Its major shortcoming in comparison
to the MMDF mailer is its primitive database facility and lack of caching.

<bf>MMDF</bf> is a comprehensive mail environment, including its own mail
composition program and of course a mailer.  There are too many parts to it
(as can be said, it is a system, not a subsystem), and the address
manipulation is only sufficient for a relatively homogenous environment. It
does have reasonable database facilities and caching, as opposed to
Sendmail, and the concept of Channels.  However, knowledge about address
semantics is distributed in several programs instead of being centralized.
<bf>PMDF</bf> is a smaller version of MMDF with correspondingly reduced features and
flexibility.

<bf>Upas</bf> is a curious approach to the problem. It lets the user do half the
work of message routing, in a manner similar to PMDF on VMS systems. It is
entirely concerned with the message envelope, and leaves all message header
munging to auxiliary programs if appropriate. In fairness one should note
this mailer was developed in an environment where most message headers were
scorned, thus making this a reasonable approach (``optimize the normal
case''). The Eighth Edition Upas had no database capability at all, but it
did exhibit one useful characteristic: the routing decisions are made by
passing the recipient envelope address through a set of regular
expressions. This production rule approach is similar to what Sendmail
does, but uses a more familiar mechanism and environment.

The final, and most recently developed, mailer worth mentioning here is
<bf>Smail3.0</bf>. It is intended as a program capable of replacing Sendmail in many
situations. To a large extent it succeeds as this, and there are some nice
ideas involved as well. Its two major drawbacks are that it is not as easy
to adapt to local needs as Sendmail is (compiled instead of interpreted
rules and algorithms), and retaining Sendmail's single-program design.  It
addresses database and caching issues, and seems generally like a nicer
design in many respects, a bit like PMDF's configuration options in a
Sendmail package.

Until the recent increase in the demand for inter-network mail gatewaying,
Sendmail's flexibility had quite adequately served to implement a gateway
function between selected networks.  With increased variety of the normal
address syntax and mail capabilities of connected networks, and more complex
kinds of routing decisions becoming necessary, the existing mailers have
been showing their age and their limits.  ZMailer is intended to give the
mail administrator a software tool that fits the times.

<!-- install.sgml -->
<sect>Build and Install
<p>This section describes how to build and install ZMailer.

<bf>Tip:</bf> Consider joining the ZMailer user-community email list.
It is the place to meet the Gurus, in case you have problems.
See the <tt>Overview</tt> file for more information.

The cornerstone of everything in busy Internet email routing
is a well-working DNS server, and modern resolver library.
If you use the BIND nameserver, you should be using (or install)
a recent version, at least BIND 4.8. In this package there is also 
a bundled resolver from  bind-4.9.4, however it is a bit difficult at 
BSD systems (because those developers use BSD themselves, and make an 
assumption that verybody has their version of things...  On the other hand,
those systems have reasonably modern resolvers, so no need to worry about it
-- I hope.) 

<bf>Note:</bf> If you are on an Ultrix system, replace the <tt>mkdep</tt> and <tt>mklibdep</tt>
scripts in the <tt>bin</tt> directory with the versions provided in <tt>bin/Ultrix</tt>.
<sect1>Autoconfiguration
<p>This system uses several preferably separate partitions for
different things:<itemize>
<item>Software binaries, and databases: &dollar;MAILVAR/, &dollar;MAILSHARE/, &dollar;MAILBIN/
<item>The mailbox spool: MAILBOX (<tt>/var/mail</tt>)
<item>The postoffice spool: POSTOFFICE (<tt>/var/spool/postoffice</tt>)
<item>The log directory: LOGDIR (<tt>/var/log/mail</tt>)
</itemize>
The GNU-autoconfig mechanism is used, however, you still may need to
touch on some files after that system has run through:
You MUST define <tt>--prefix=</tt> so that ZMailer components end up
in reasonable places.  The MAILBIN (and MAILSHARE, and MAILVAR)
variable values are derived from the <tt>--prefix=</tt>, which can cause
surprises if you do <tt>make install</tt> with GNU autoconfig defaults.

Also, if the <tt>/etc/zmailer.conf</tt> file exists, it is read
to initialize several different environment paths (including
MAILBIN, et.al.!)
<tscreen><verb>
# ./configure --prefix=/opt/mail                              \
              --with-postoffice=/var/spool/postoffice	      \
              --with-mailbox=/var/mail			      \
              --with-logdir=/var/log/mail		      \
              --with-zmailer-conf=/etc/zmailer.conf
</verb></tscreen>
Or an example from my development machine:
<tscreen><verb>
$ ./configure --prefix=/opt/mail
creating cache ./config.cache
***
*** You can set  ZCONFIG  environment variable to define
*** the location of the (default) /etc/zmailer.conf -file
*** (You can use also   --with-zconfig=  -parameter)
***
*** Consider also setting following parameters:
***   --mandir=DIR     -- for man-pages
***   --libdir=DIR     -- for libzmailer(3)
***   --includedir=DIR -- for libzmailer(3)
*** (They can be outside the --prefix=DIR -tree)
***
*** You can set CC, and CFLAGS  environment variables to
*** choose the C-compiler, and its options, especially at
*** systems where there are multiple choices to use...
***
</verb></tscreen>
See if <tt>SiteConfig</tt> makes sense now, if not, you can tune
most of the values with various <tt>--with-*=</tt> keywords:
<tscreen><verb>
./configure --help
</verb></tscreen>
and those that you can't tune, you can edit at the <tt>SiteConfig.in</tt>
file.  (Redo the configure with new parameters, if it looks to be
necessary.)

Additional examples:
<itemize><item>DEC OSF/1 at nic.funet.fi with DECs best compiler...
<tscreen><verb>
CFLAGS="-O -g3 -std1" CC="cc -migrate" ./configure   \
	--prefix=/l/mail  --with-bundled-libresolv   \
	--with-system-malloc
</verb></tscreen>
<item>Sun Solaris 2.5  at mailhost.utu.fi, SunSoft CC 
<tscreen><verb>CC="cc -O" ./configure --prefix=/opt/mail	\
	--with-bundled-libresolv
</verb></tscreen>
<item>Sun Solaris 2.5  at mailhost.utu.fi, gcc-2.7.2
<tscreen><verb>./configure --prefix=/opt/mail --with-bundled-libresolv \
	--with-gcc
</verb></tscreen>
<item>Linux-2.0.x/libc-5.4.2 at mea.cc.utu.fi, gcc-2.7.2 
<tscreen><verb>./configure --prefix=/l/mail
</verb></tscreen>
</itemize>
<sect1>Compilation
<p>At the toplevel, run
<tscreen><verb>make</verb></tscreen>
or perhaps:
<tscreen><verb>make clean all</verb></tscreen>
which at first cleans everything, and then makes -- great if you
changed some configuration parameters.

This should compile everything, and leave a <tt>zmailer.Config</tt> file in
the toplevel directory.  Nothing outside the source area will be
touched at this point.

(If your system ``make'' lets your shell ``SHELL''-environment
affect its own execution environment, it may be that non sh/ksh/zsh
users detect weird phenomena, and failures. Beware!)

<sect1>Installing and Upgrading
<p>This section describes how to install or upgrade ZMailer.

<sect2>Preparation
<p>If you are currently running a zmailer, kill off all mailer processes
using
<tscreen><verb>zmailer kill</verb></tscreen>
and save the state of your system.  This includes any active
contents of the postoffice, as well as database files and
anything else in the installation areas you want to be sure
to keep.  This is just paranoia, the installation should not
overwrite precious files, and will save old versions of
distribution files in ``bak'' subdirectories.

The interface in between the commonly used sendmail, and ZMailer
is a ``compability program'', which is to replace the <tt>/usr/lib/sendmail</tt>
(aka <tt>/usr/sbin/sendmail</tt> on some systems).
The system attempts to automate the replacement, but it MAY present
a cry for help, if your system does not have functioning symlinks.
Also if <tt>test -h &dollar;(SENDMAILPATH)</tt> does fault in mysterious ways,
the reason may be that your system does not have symlinks.

If you are currently running Sendmail, kill your SMTP server
and drain the Sendmail queue.  There is no automatic method
to requeue Sendmail messages under ZMailer.  If you later want
to back out to Sendmail, all you need to do is move the former
version of the sendmail (on <tt>/usr/lib/sendmail.bak</tt>, for example)
binary back to <tt>/usr/lib/sendmail</tt>.

(You may also need to do some magics with system startup scripts
in case you are running SysV-style init. BSD <tt>/etc/rc.local</tt>
does need its own gymnastics too.)

A sort of method to quickly handle your sendmail queue is to
start ZMailer's SMTP server, reconfigure the old sendmail to
use smarthost, which happens to be at the same machine.
(Or at an adjacent machine if you moved the queue, or ...)
Anyway the point is to get the sendmail to send its queue
via SMTP to the ZMailer.

<sect2>Installation
<p>Once you are safe, run either:
<tscreen><verb># make install</verb></tscreen>
(this installs all binaries and the default database files, which
still need editing! See below.)
or if you just want to have the new BINARIES without touching
at your configurations:
<tscreen><verb># make install-bin</verb></tscreen>
All programs are stored into  <tt>&dollar;MAILBIN/</tt>, and <tt>&dollar;MAILBIN/ta/</tt>, and
possible older binaries are saved into ``bak'' subdirectories.
This step should be non-destructive (anything replaced will be
saved in a ``bak'' directory, and for some customizable files, if
they exist new versions won't replace them).

If this is not a from-scratch installation, be aware that the
install procedure will NOT replace some of the files in MAILSHARE
with the equivalents from the distribution.  Specifically, the
<tt>&dollar;MAILSHARE/cf/*</tt>, <tt>&dollar;MAILVAR/db/aliases</tt>, <tt>&dollar;MAILVAR/db/routes</tt>, and
<tt>&dollar;MAILVAR/db/localnames</tt> files are never replaced if they already
exist.  The <tt>&dollar;MAILSHARE/forms/*</tt> files are always replaced, but the
old files will be saved in a ``bak'' directory.

<sect3>The Router Configuration File (&dollar;MAILSHARE/router.cf).
<p>

You must now pick a toplevel router configuration file.  The
default is provided in <tt>proto/cf/SMTP+UUCP.cf</tt> (by now copied to
<tt>&dollar;MAILSHARE/cf/SMTP+UUCP.cf</tt>). You need to create <tt>&dollar;MAILSHARE/router.cf</tt>.
The simplest method is to make it symbolic link to, or copy of,
the <tt>cf/SMTP+UUCP.cf</tt> file.
Some real-life samples of <tt>router.cf</tt> are at the <tt>proto/</tt> directory.

<sect3>Installing the Manual Pages.
<p>

Go into the <tt>man</tt> directory, and install the manual pages by hand:
<tscreen><verb>cd man ; make install</verb></tscreen>
or in case the default guessing didn't get it right:
<tscreen><verb>cd man ; make install MANDIR=/our/manpages</verb></tscreen>

<sect1>Configuring
<p>This section describes the configuration in short. More detailed information 
can be found in section <em>xxxxx....</em>.
<sect2>/etc/mail.conf
<p>If you are using the default configuration setup, the <tt>router.cf</tt> file
expects to find a <tt>/etc/mail.conf</tt> file containing three variable
definitions:
<tscreen><verb># Where am I?
orgdomain=domain
# Who am I?
hostname=host.subdomain.$orgdomain
# Who do I claim to be?
mydomain=subdomain.$orgdomain
</verb></tscreen>
For example:
<tscreen><verb>
orgdomain=toronto.edu
hostname=relay.cs.$orgdomain
mydomain=cs.$orgdomain
</verb></tscreen>
Create <tt>/etc/mail.conf</tt> with appropriate contents.  If you are a
multi-host site, determining these things can be automated according
to your local policies and conventions.  See the files specific to
the University of Toronto (<tt>UT*.cf</tt>) for examples of this.

Location of this file is written in <tt>&dollar;MAILSHARE/router.cf</tt>, at which
you can alter it. Into <tt>&dollar;MAILSHARE/mail.conf</tt> -- for example.
<sect2>/etc/group
<p>The default configuration also expects to find names of trusted users
listed at  <tt>/etc/group</tt> entry <tt>zmailer</tt>.  Users (unames) listed there
will be able to claim any addresses at the message headers, etc.
(See <tt>&dollar;MAILSHARE/cf/trusted.cf</tt> for its usage there.)
Usual set is: <tt>root,daemon,uucp</tt>.
(Note: At some machines `daemon' is called `daemons'; it is
the one with UID=1)

<bf>SECURITY ITEM:</bf> Those users at <tt>zmailer</tt> group <bf>must not</bf> contain <tt>nobody</tt>!
(The <tt>nobody</tt> is used to prevent externally given inputs from being
able to execute arbitary programs at the system, or from writing to
arbitary files.)

<sect2>Verifying That the Router Starts
<p>At this point, you should be able to start the router process in
interactive mode.  Run:
<tscreen><verb>$MAILBIN/router -i</verb></tscreen>
or
<tscreen><verb>/usr/lib/sendmail -bt</verb></tscreen>
You should see something like:
<tscreen><verb>
ZMailer router (2.99.49p5 #4: Wed Jul 23 01:24:37 EET DST 1997)
you@hostname:/some/path/to/src/zmailer/router
Copyright 1992 Rayan S. Zachariassen
Copyright 1992-1997 Matti Aarnio

z#    
</verb></tscreen>

If there are errors in the configuration file, you will be told here.
The `z&num;' is the interactive prompt for root. It is unlikely you can do anything useful 
before setting up the data files, so get out of this by hitting EOF, or type <tt>exit</tt>.

<sect2>The Database and Forms Files
<p>Now you should merge, replace, or check the default database and
forms files with your previous setup.

Pay particular attention to the following items:
<itemize>
<item>You may want to add a symbolic link from some directory in your path
to <tt>&dollar;MAILBIN/zmailer</tt>, if you don't already have this.  I put this link
in <tt>/usr/local/sbin</tt>.
<item><tt>&dollar;MAILVAR/db/aliases</tt> file:	The provided skeleton aliases file on purpose contains syntax errors,
so you are reminded to change the contents.

The aliases database is rebuilt using the <tt>&dollar;MAILBIN/newaliases</tt> script.
This can be invoked in several ways: directly as a command if you
have <tt>/usr/ucb/newaliases</tt> symlinked properly, or by <tt>zmailer newaliases</tt>
or <tt>sendmail -bi</tt> if the ZMailer sendmail replacement is installed.

Choose one of the following methods to rebuild the database:
<tscreen><verb>
# $MAILBIN/newaliases
# $MAILBIN/zmailer newaliases
# /usr/lib/sendmail -bi
# ln -s /usr/lib/sendmail /usr/ucb/newaliases ; /usr/ucb/newaliases
</verb></tscreen>
If there are errors, correct them in the <tt>&dollar;MAILVAR/db/aliases</tt> file
and repeat the command until the alias database has been initialized.
The final message should look something like:
<tscreen><verb>319 aliases, longest 209 bytes, 16695 bytes total
</verb></tscreen>
See also IETF's RFC 2142: ``Mailbox Names for Common Services, Roles and
Functions'' (file <tt>rfc2142.txt</tt> in the <tt>doc/rfc</tt> directory) 
for other suggestable aliases you may need. 
                                                               

<item><tt>&dollar;MAILVAR/db/localnames</tt> file: Add the hostnames you want ZMailer to do local delivery for, to the
<tt>&dollar;MAILVAR/db/localnames</tt> file.  Due to my own belief in Murphy,
I usually add partially qualified domain names and nicknames in
addition to canonicalized names.  If you want to do local delivery
for mail clients, put their names in here too.  You may use pathalias 
style .domain names in this file, to indicate everything under some
subdomain. <bf>Remember to sort the file.</bf>

With the sample config files for mea's Zmailer-2.98, and latter
this <tt>localnames</tt> is actually a mapping of those various names to
the desired forms of the canonic name, thus an example:
<tscreen><verb>
astro.utu.fi		astro.utu.fi
oj287			astro.utu.fi
oj287.astro.utu.fi	oj287.astro.utu.fi
oj287.utu.fi		astro.utu.fi
sirius			sirius.utu.fi
sirius.astro.utu.fi	sirius.utu.fi
sirius.utu.fi		sirius.utu.fi
</verb></tscreen>
REMEMBER: ALL NAMES THAT THE HOST MAY EVER HAVE ARE BEST LISTED
IN HERE!  It reminds you of them, and makes sure a message
destined into the host really is accepted.

<item><tt>&dollar;MAILVAR/db/routes</tt> file: Add any UUCP neighbours or other special cases to this file.  For
example (remember to keep the entries sorted):
<tscreen><verb>
.toronto.ca			error!err.wrongname
.toronto.cdn			error!err.wrongname
alberta				uucp!alberta
atina				smtp![140.191.2.2]
calgary				smtp!cs-sun-fsa.cpsc.ucalgary.ca
icnucevm.bitnet			smtp!icnucevm.cnuce.cnr.it
</verb></tscreen>
<item><tt>&dollar;MAILVAR/db/fqdnaliases</tt> file: The <tt>fqdnaliases</tt> database is for mapping fully-qualified user
addresses to others -- for example you machine has a set of
domain-names for it to consider local, but you want to have
separate people to be postmasters for each of them:
<tscreen><verb>postmaster@domain1: person1
postmaster@domain2: person2
postmaster@domain3: person3
</verb></tscreen>
This facility is always in stand-by -- just add the file, and
you have it.

You may even handle just a few users for each of those domains, and
then have the <tt>routes</tt> entry (see above) to declare something suitable:
<tscreen><verb>.domain1	error!nosuchuser
</verb></tscreen>
which combined with the <tt>fqdnalias</tt> method will let <tt>postmaster@domain1</tt>
to exist, and report error on all others.

The <tt>fqdnaliases</tt> database is rebuilt using the <tt>&dollar;MAILBIN/newfqdnaliases</tt>
script.  This can be invoked in several ways: directly as a command
by executing <tt>&dollar;MAILBIN/newfqdnaliases</tt>, or by <tt>zmailer newfqdnaliases</tt>.

Choose one of the following methods to rebuild the database:
<tscreen><verb># $MAILBIN/newfqdnaliases</verb></tscreen>
or
<tscreen><verb># $MAILBIN/zmailer newfqdnaliases
</verb></tscreen>

If there are errors, correct them in the <tt>&dollar;MAILVAR/db/fqdnaliases</tt> file
and repeat the command until the alias database has been initialized.
The final message looks similar to that of the ordinary aliases case.
</itemize>

<sect2>UUCP and BITNET Node Names
<p>If your hostname and UUCP node name are not identical, put your
UUCP node name in the file <tt>/etc/name.uucp</tt> (or <tt>/etc/uucpname</tt>).

If you are on BITNET, put your BITNET node name in <tt>/etc/name.bitnet</tt>
(or <tt>/usr/lib/urep/BITNETNAME</tt>). (And if you really need BITNET stuff, have a look at:
<tt>ftp://ftp.funet.fi/pub/unix/networking/bitnet/</tt>)

<sect2>Checking the Routing
<p>At this point, you should be able to start the router again in
interactive mode, and ask it to route addresses.  Try:
<tscreen><verb>
/usr/lib/sendmail -bt
</verb></tscreen>
at the prompt:
<tscreen><verb>z# router you</verb></tscreen>
should print out:
<tscreen><verb>
(((local you you default_attributes)))
</verb></tscreen>

Keep playing around with various addresses until you get a feel for it.
Modify the configuration file if your setup requires it.

<sect2>/etc/services
<p>Add the following line to <tt>/etc/services</tt> in the section for
host-specific services:
<tscreen><verb>mailq		174/tcp			# Mailer transport queue</verb></tscreen>

<sect2>Bootup Scripts
<p>Add something like the following lines to bootup scripts (<tt>/etc/rc.local</tt>
or <tt>/etc/rc2.d/S99local</tt> or similar):
<tscreen><verb>
if [ -r /etc/zmailer.conf ]; then
(
	. /etc/zmailer.conf
	if [ ${MAILSERVER-NONE} = NONE -a -x $MAILBIN/zmailer ]; then
		$MAILBIN/zmailer bootclean
		$MAILBIN/zmailer &ero; (echo -n ' zmailer')	>/dev/console
	fi
)
fi
</verb></tscreen>
For SysV-init environments, see <tt>utils/zmailer.init.sh</tt>.
You may want to comment out startup of the Sendmail daemon, if you have it to begin with.

<sect2>Checking the Log Files
<p>Start ZMailer:
<tscreen><verb>$MAILBIN/zmailer</verb></tscreen>

Keep an eye on the log files (<tt>&dollar;LOGDIR/{router,scheduler}</tt>),
the <tt>&dollar;POSTOFFICE/postman</tt> directory for malformed message files,
and <tt>&dollar;POSTOFFICE/deferred</tt> in case of resource problems.

<sect2>Crontab
<p>Add the following entry (or equivalent) to your <tt>crontab</tt>:
<tscreen><verb>
28 0,8,16 * * * . /etc/zmailer.conf ; $MAILBIN/zmailer resubmit
</verb></tscreen>
This will resubmit messages that have been deferred with no
useful processing possible at time of deferral.  Adjust the
resubmission interval to suit your environment.

You may also want to regularly clean out the <tt>&dollar;POSTOFFICE/public</tt>
and <tt>&dollar;POSTOFFICE/postman</tt> directories:
<tscreen><verb>
7 4 * * * . /etc/zmailer.conf ; $MAILBIN/zmailer cleanup
</verb></tscreen>
You may want to hardwire the location of the zmailer script.

<sect2>Customizing ZMailer Messages
<p>Edit several of the canned error messages and programs (scripts)
to reflect your local configuration: <tt>&dollar;MAILSHARE/forms/</tt> files and
<tt>&dollar;MAILBIN/ta/usenet</tt> (injected message).

<sect2>Alias expansion
<p>Read the notes on alias expansion in the file <tt>doc/guides/aliases</tt> and
on mailing list maintenance in <ref id="mailing_list_maintenance">, 
Mailing Lists and ~/.forward, page <pageref id="mailing_list_maintenance">.

<sect2>Trimdown of Logging
<p>Once satisfied that things appear to work, you may want to trim down
logging: there are 4 kinds of logging to deal with:
<itemize><item>router logs, usually kept in <tt>&dollar;LOGDIR/router</tt>.  This is the stdout
and stderr output of the router daemon.  If you wish to turn it off,
invoke router with a <tt>-L/dev/null</tt> option, i.e. change the zmailer
script.  Alternatively, modify the <tt>log()</tt> function in the
configuration file, or its invocations.

*** NOTE, THIS IS INCORRECT INFO, see  &dollar;MAILSHARE/cf/standard.cf for
*** routine   dribble(),  and especially its invocations!
<item>scheduler logs, usually kept in <tt>&dollar;LOGDIR/scheduler</tt>.  Same as router.
<item>general mail logs, usually kept in syslog files, depending on how
you have configured the syslog utility (<tt>/etc/syslog.conf</tt>).  All
ZMailer programs log using the LOG_MAIL facility code for normal
messages.  You can deal with this specifically in your <tt>syslog</tt>
configuration file on systems with a 4.3bsd-based syslog.  The
following reflects the recommended configuration on SunOS 4.0:
<tscreen><verb>
mail.crit		/var/log/syslog
mail.debug		/var/log/mail
</verb></tscreen>
For pre-4.3bsd-based syslogs, you may want the syslog log file
to be just for important messages (e.g. LOG_NOTICE and higher
priority), and have a separate file for informational messages
(LOG_DEBUG and up).
<item>By default, the postmaster will receive a copy of all bounced
mail; this can be turned off selectively by simply editing the
various canned forms used to create the error messages.  These
forms are located in the FORMSDIR (<tt>proto/forms</tt> in the distribution,
or <tt>&dollar;MAILSHARE/forms</tt> when installed).  You should review these
in any case to make sure the text is appropriate for your site.
</itemize>

<sect1>Installation on Clients
<p>This section describes the installation on clients.
<sect2>Required Files
<p>The following files/programs are needed on clients:
<itemize><item><tt>/etc/zmailer.conf</tt> - the MAILSERVER variable may be set to the
mail server host's name.  This is not required as <tt>mailq</tt> will usually be able
to discover this by itself.
<item><tt>/usr/lib/sendmail</tt> - to submit mail
<item><tt>mailq</tt> - should be installed in the site's local
<tt>bin</tt> so people can query the mail server. (Remember to update <tt>/etc/services</tt>)
<item><tt>&dollar;POSTOFFICE</tt> - this directory from the server should be mounted and writable.
</itemize>

<sect2>Mounting MAILBOXes and/or POSTOFFICE Hierarchies via NFS
<p>Mostly at client machines, but also at servers.

If you for some obscure reason are mounting MAILBOXes
and/or POSTOFFICE hierarchies via NFS, do it with
options to disable various attribute caches:
<tscreen><verb>
		actimeo=0
alias:		noac
</verb></tscreen>
The best advice is to NOT to mount anything over NFS,
but some people can't be persuaded...

Lots of things are done where file attributes play important
role, and they are extremely important to be in sync!
(Sure, the `noac' slows down the system, but avoids errors
caused by bad caches.)

If you are mounting people's home directories (<tt>.forward</tt> et al.)
via NFS, consider the same rule!

Often if the mail folder directory is shared, also (depending upon the system):
<tscreen><verb>
/usr/mail
/usr/spool/mail
/var/mail
/var/spool/mail
</verb></tscreen>

<sect1>Verifying the System
<p>Text to be inserted here.

<!-- admin.sgml -->
<sect>Administration
<p>

<sect1>DNS and ZMailer
<p>

The cornerstone of everything in busy Internet email routing is a properly
working DNS server, and a modern resolver library. If you use the BIND 
nameserver, you should be using a recent version, at least BIND 4.8.
(As of this writing, bind is on version 8.1.1)

You can get improved DNS performance by installing local <tt>named</tt>,
which does cache replies, including <bf>negative</bf> replies.

For the file <tt>/etc/resolv.conf</tt>:
<tscreen><verb>
domain  your.domain
nameserver 127.0.0.1
nameserver  (some other server)
</verb></tscreen>

For the local nameserver daemon (<em>named</em>) you should have
at least following type of configuration:
<tscreen><verb>
forwarders 10.12.34.56  10.45.67.89
options forward-only
</verb></tscreen>
which means that all the queries are attempted to be resolved
by the servers at IP addresses <em>10.12.34.56</em> and
<em>10.45.67.89</em>, and both the local server, and remote
servers will cache DNS responses.

<sect1>Security Issues
<p>

Having local-parts that allow delivery to arbitary files, or which can trigger
execution of arbitrary programs, can clearly lead to a huge security
problem.  <em>sendmail</em> does address this problem, but in a restrictive and
unintuitive manner.  This aspect of ZMailer security has been designed to
allow the privileges expected by common sense.

The responsibility for implementing this kind of security is split between
the <em>router</em> and the transport agent that delivers a message to
an address.
Since it is the Transport Agent that must enforce the security, it needs
some information to guide it.  Specifically, for each address it delivers
to, some information about the ``trustworthyness'' of that address is
necessary so the transport agent can determine which privileges it can
assume when delivering for that destination.  This information is
determined by the <em>router</em>, and passed to the transport agent in the message
control file.  The specific measure of trustworthyness chosen by ZMailer, 
is simply a user id (uid) value representing the source of the address.

When a message comes in from a non-local host, the destination addresses
should obviously have no privileges on the local host (when mailing to a
file or a program).  Similarly, common sense would indicate that locally
originated mail should have the same privileges as the originator.  Based
on an initial user id assigned from such considerations, the privilege
attached to each address is modified by the attributes of the various alias
files that contain expansions of it.  The algorithm to determine the
appropriate privilege is to use the user id of the owner of the alias file
if and only if that file is not group or world writable, and the directory
containing the file is owned by the same user and is likewise neither group
nor world writable.  If any of these conditions do not hold, an
unprivileged user id will be assigned as the privilege level of the
address.


It is entirely up to the transport agent whether it will honour the
privilege assignment of an address, and indeed in many cases it might not
make sense (for example for outbound mail).  However, it is strongly
recommended that appropriate measures are taken when a transport agent has
no control over some action that may affect local files, security, or
resources.


The described algorithm is far from perfect. The obvious dangers are:

<itemize>
<item>The grandparent directories, to the Nth degree, are ignored, and may
not be secure. In that case all security is lost.
<item>There is a window of vulnerability between when the permissions are
checked, and the delivery is actually made. This is the best argument
I have heard so far for embedding the local delivery program
(currently a separate transport agent) in the <em>router</em>.
</itemize>

There is also another kind of security that must be addressed.  That is the
mechanism by which the <em>router</em> is told about the origin of a message.  This
is something that must be possible for the message receiving programs
(<tt>/bin/rmail</tt> and the SMTP server are examples of these) to specify to
ZMailer.  The <em>router</em> knows of a list of trusted accounts on the system.  If
a message file is owned by one of these user id's, any sender specification
within the message file will be believed by ZMailer.  If the message file
is not owned by such a trusted account, the <em>router</em> will cross-check the
message file owner with any stated <tt>From:</tt> or <tt>Sender:</tt> address 
in the message header, or any origin specified in the envelope.  If a 
discrepancy is discovered, appropriate action will be taken.  This means 
that there is no way to forge the origin of a message without access to a 
trusted account.

Trusted accounts are those listed in the ZMailer group or the ``trusted'' 
variable in the system configuration (<em>router.cf</em>) file.

<sect1>The Queue
<p>
There are multiple queues in ZMailer. Messages exist in
in one of five locations:

<itemize>
<item>Submission temporary directory (<tt>&dollar;POSTOFFICE/public/</tt>)
<item>Freezer directory (<tt>&dollar;POSTOFFICE/freezer/</tt>)
<item>Router directory (<tt>&dollar;POSTOFFICE/router/</tt>)
<item>Deferred directory (<tt>&dollar;POSTOFFICE/deferred/</tt>)
<item>Scheduler directories (<tt>&dollar;POSTOFFICE/transport/</tt>, 
<tt>&dollar;POSTOFFICE/queue/</tt>)
</itemize>
and sometimes is also copied into the 
<itemize>
<item>Postmaster analysis area (<tt>&dollar;POSTOFFICE/postman/</tt>)
</itemize>

<sect2>Message Submission Areas
<p>

Message submission is done by writing a temporary file
into the directory (<tt>&dollar;POSTOFFICE/public/</tt>), the 
actual format of the submitted message is described in Appendix D.1.

Insert xref!

When the temporary file is completely written, it is renamed into one 
of the <em>router</em> input directories, usually into 
<tt>&dollar;POSTOFFICE/router/</tt> with a name that is a decimal representation
of the file i-node number. This is a way to ensure that the
name of the file in the <tt>&dollar;POSTOFFICE/router/</tt> directory is unique.

The message may also be renamed into alternate router directories, 
which give lower priorities on which messages to process when.

Sometimes, especially <em>smtpserver</em> built files may be moved
into alternate directories. The smtpserver <tt>ETRN</tt>
command is implemented by moving the built special file to the 
directory <tt>&dollar;POSTOFFICE/transport/</tt> without going through the
<em>router</em>.  The smtpserver may also move newly arrived
files into the <tt>&dollar;POSTOFFICE/freezer/</tt> directory.

<sect2>Router Behaviour on Queues
<p>

The <em>router</em> processes have a few different behaviours when
they go over their input directories.

First of all, if there are <tt>ROUTERDIRS</tt> entries, those
are scanned for processing after the primary 
<tt>&dollar;POSTOFFICE/router/</tt> directory is found empty.

Within each directory, the <em>router</em> will sort files at first into 
mod-time order, and then process the oldest message first. (Unless the 
<em>router</em> has been started with the `-s' option.)

The <em>router</em> acquires a lock on the message (spool file) by means
of renaming the file from its previous name to a name with the format: 
<tt>concat(file_ino_number,"-",progpid)</tt>

Once the <em>router</em> has been able to acquire a new name
for the file, it starts off by creating a temporary file of
<em>router</em> routing decisions.  The file has a name with the format:
<tt>concat("..",file_ino_number,"-",progpid)</tt>

Once the processing has completed successfully, the original
input file is moved into the directory <tt>&dollar;POSTOFFICE/queue/</tt>, and
the <em>router</em> produced scheduler work-specification file is moved
to the <tt>&dollar;POSTOFFICE/transports/</tt> directory with the <bf>same</bf>
name that the original file has.

If the routing analysis encountered problems, the message
may end up moved into the directory <tt>&dollar;POSTOFFICE/deferred/</tt>, from
which the command <tt>zmailer resubmit</tt> is needed to return 
the messages to processing. (The <em>router</em> logs should be consulted 
for the reason why the message ended up in the <em>/deferred/</em> area,
especially if the command <tt>zmailer resubmit</tt> is not able
to get the messages processed successfully and
the files end up back in the <em>/deferred/</em> area.)

If the original message had errors in its RFC-822 compliance,
or some other detail, a copy of the message may end up in the 
directory <tt>&dollar;POSTOFFICE/postman/</tt>.  

See 
<x>section</x>
<ref id="postmaster_analysis_area" name="Postmaster Analysis Area">
<x>, Postmaster Analysis Area, page </x>
<pageref id="postmaster_analysis_area">.

<sect2>Scheduler and Transport Agents
<p>

The scheduler work specification files are in the directory
<tt>&dollar;POSTOFFICE/transport/</tt>, under which there can be (optionally)
one or two levels of subdirectories into which the actual
work files will be scattered to lessen the sizes of individual
directories in which files reside, and thus to speed up the
system implied directory lookups at the transport agents, when
they open files, (and also in the scheduler).

When the <em>router</em> has completed message file processing, it places the
resulting files into the top level directory of the scheduler; 
<tt>&dollar;POSTOFFICE/transport/</tt>, and <tt>&dollar;POSTOFFICE/queue/</tt>.

The scheduler (if so configured) will move the messages into 
``hashed subdirectories,'' when it finds the work specification files, 
and then start processing addresses in them.

The transport agents are run with their CWD in directory 
<tt>&dollar;POSTOFFICE/transport/</tt>, 
and they open files relative to that location. Actual message bodies, when 
needed, are opened with the path prefix ``<tt>../queue/</tt>'' to the work 
specification file name.

Usually it is the transport agent's duty to log different permanent status reports 
(failures, successes) into the end of the work-specification file.  
Sometimes the scheduler also logs something at the end of this file.  
All such operations are attempted <bf>without</bf> any sort 
of explicit locking, instead trusting the <em>write(2)</em> system call to 
behave in an atomic manner while writing to the disk file, and 
having a single buffer of data to write.

Once the scheduler has had all message recipient addresses 
processed by the transport agents, it will handle possible
diagnostics on the message, and finally it will remove the
original spool-file from the <tt>&dollar;POSTOFFICE/queue/</tt>, and 
the work-specification file from <tt>&dollar;POSTOFFICE/transport/</tt>.

<sect2>Postmaster Analysis Area<label id="postmaster_analysis_area">
<p>

If the filename in the <tt>&dollar;POSTOFFICE/postman/</tt> directory has an 
underscore in it, the reason for the copy is <bf>soft</bf>, that is, the 
message has been sent through successfully in spite of being copied into
the <tt>&dollar;POSTOFFICE/postman/</tt> directory.

If the filename in the <tt>&dollar;POSTOFFICE/postman/</tt>
<em>does not have an underscrore in it, that file has not been processed
successfully, and the</em> <bf>only</bf> <em>copy of the message
is now in <tt>&dollar;POSTOFFICE/postman/</tt></em>

If the  smtpserver  receives a message with content that the policy filtering
system decides to be dubious, it can move the message into
<tt>&dollar;POSTOFFICE/freezer/</tt> directory with a bit explanatory name of type:
<tt>concat(file_ino_number,"explanatory-text")</tt>.

The files in that area are such that they are input to the router, and
as of this wiring, there are no tools to automatically process them for
obvious spams, and just those were falsely triggered.

<sect1><label id="Logging_and_Statistics">Logging and Statistics 
<p>
This text has been copied from other sections and will change...

<sect2>Logging
<p>
<sect2>Checking the Log Files
<p>Start ZMailer:
<tscreen><verb>$MAILBIN/zmailer</verb></tscreen>

Keep an eye on the log files (<tt>&dollar;LOGDIR/{router,scheduler}</tt>),
the <tt>&dollar;POSTOFFICE/postman</tt> directory for malformed message files,
and <tt>&dollar;POSTOFFICE/deferred</tt> in case of resource problems.

<sect2>Trimdown of Logging
<p>Once satisfied that things appear to work, you may want to trim down
logging: there are 4 kinds of logging to deal with:
<itemize><item>router logs, usually kept in <tt>&dollar;LOGDIR/router</tt>.  This is the stdout
and stderr output of the router daemon.  If you wish to turn it off,
invoke router with a <tt>-L/dev/null</tt> option, i.e. change the zmailer
script.  Alternatively, modify the <tt>log()</tt> function in the
configuration file, or its invocations.

*** NOTE, THIS IS INCORRECT INFO, see  &dollar;MAILSHARE/cf/standard.cf for
*** routine   dribble(),  and especially its invocations!
<item>scheduler logs, usually kept in <tt>&dollar;LOGDIR/scheduler</tt>.  Same as router.
<item>general mail logs, usually kept in syslog files, depending on how
you have configured the syslog utility (<tt>/etc/syslog.conf</tt>).  All
ZMailer programs log using the LOG_MAIL facility code for normal
messages.  You can deal with this specifically in your <tt>syslog</tt>
configuration file on systems with a 4.3bsd-based syslog.  The
following reflects the recommended configuration on SunOS 4.0:
<tscreen><verb>
mail.crit		/var/log/syslog
mail.debug		/var/log/mail
</verb></tscreen>
For pre-4.3bsd-based syslogs, you may want the syslog log file
to be just for important messages (e.g. LOG_NOTICE and higher
priority), and have a separate file for informational messages
(LOG_DEBUG and up).
<item>By default, the postmaster will receive a copy of all bounced
mail; this can be turned off selectively by simply editing the
various canned forms used to create the error messages.  These
forms are located in the FORMSDIR (<tt>proto/forms</tt> in the distribution,
or <tt>&dollar;MAILSHARE/forms</tt> when installed).  You should review these
in any case to make sure the text is appropriate for your site.
</itemize>


<sect2>Scheduler Statistics log
<p>
The  statistics log reports condenced performance oriented
information in following format:
<tscreen><verb>
timestamp fileid      dt1  dt2 state $channel/$host
812876190 90401-2	0    5	  ok usenet/-
812876228 90401-1	0    7	  ok usenet/-
812876244 90401-1	0    1	  ok local/gopher-admin
812876244 90401-1	0    5	  ok smtp/funet.fi
812876559 90401-1	0   21	  ok smtp/utu.fi
</verb></tscreen>
       where the fields are:
<descrip>
<tag/timestamp/ The original spoolfile <tt>ctime</tt> (creation time)  stamp
in decimal.

<tag/fileid/ Spoolfile name after the router has processed it.

<tag/dt1/ The time difference from spoolfile ctime to 
scheduler control file creation by the router.

<tag/dt2/ The time difference from scheduler file <tt>ctime</tt> to
the delivery that is logged on.

<tag/state/ What happened?  Values: <tt>ok</tt>, <tt>error</tt>, <tt>expiry</tt>

<tag/&dollar;channel-&dollar;host/ Where/how it was processed.
</descrip>



<sect1>SMTP-Server Configuration
<p>
<tt>MAILSHARE/smtpserver.conf</tt>

The <em>smtpserver</em> program actually has several operational modes.
It can operate as a stand-alone internet service socket listener, which
forks off childs that do the actual SMTP-protocol service.

It can be started from under the control of the inetd server, and it can
there fulfill the same role as it does stand-alone mode.

It can even be used to accept Batch-SMTP from incoming files (UUCP,
and BITNET uses, for example).

Usage

<tt>smtpserver &lsqb; -46aignvBV &rsqb; &lsqb; -p port &rsqb; &lsqb; -l logfile 
&rsqb; &lsqb; -s &lsqb;ftveR&rsqb; &rsqb; &lsqb; -L maxloadaver &rsqb; &lsqb; 
-M SMTPmaxsize &rsqb; &lsqb; -P postoffice &rsqb; &lsqb; -R router &rsqb; 
&lsqb; -C cfgfile &rsqb;</tt>

The commonly used command line options are:

<tt>smtpserver &lsqb;-aBivn&rsqb; &lsqb;-s ehlo-styles&rsqb; &lsqb;-l 
logfile&rsqb; &lsqb;-C cfgpath&rsqb;</tt>

Without any arguments the  smtpserver  will start as a daemon
listening on TCP port 25 (SMTP).

The options are:

<descrip>
<tag/<tt>-a</tt>/ Query IDENT information about the incoming connection. This information (if available at all) may, or may not tell who is forming a connection.
<tag/<tt>-B</tt>/ The session is Batch-SMTP a.k.a. BSMTP type of session. Use of "-i" option is needed, when feeding the input batch file.
<tag/<tt>-i</tt>/ This is interactive session.  IO is done thru stdin/stdout.
<tag/<tt>-v</tt>/ Verbose trace written to stdout for use in conjunktion with "-i", and "-B".
<tag/<tt>-n</tt>/ This tells that the smtpserver is running under inetd, and that the stdin/stdout file handles are actually network sockets on which we can do peer identity lookups, for example.
<tag/<tt>-s ehlo-style</tt>/ Default value for various checks done at MAIL FROM, RCPT TO, VRFY, and EXPN commands. These are overridden with the value from EHLO-patterns, if they are available (more below)
<tag/<tt>-l logfilepath</tt>/ Filename for the smtpserver input protocol log. This logs about everything, except actual message data...
<tag/<tt>-C configfilepath</tt>/ Full path for the smtpserver configuration in case the default location can not be used for some reason.
<tag/<tt>-M</tt>/ SMTPmaxsize Defines the asolute maximum size we accept from incoming email. (Default: infinite) (This is a local policy issue.)
</descrip>

<bf>Configuration</bf>

If the system has file  <tt>&dollar;MAILSHARE/smtpserver.conf</tt> (by default),
that file is read for various parameters, which can override a few
of those possibly issued at the command line.

Example (shortened) configuration is:

<tscreen><verb>
#PARAM maxsize              10000000	# Same as -M -option
#PARAM max-error-recipients        3	# More than this is propably SPAM!
#PARAM MaxSameIpSource		  10    # Max simultaneous connections from
#					# any IP source address
#PARAM ListenQueueSize		   5	# The  listen(2)  parameter
#
PARAM help -------------------------------------------------------------
PARAM help  This mail-server is at Yoyodyne Propulsion Inc.
PARAM help  Our telephone number is: +1-234-567-8900, and
...
PARAM help -------------------------------------------------------------
#
PARAM	accept-percent-kludge # "localpart" can contain '%' and '!'
#PARAM	reject-percent-kludge # "localpart" can't contain  --"--
#
#  Uncomment this for not to strip source routes from:  <@a,@b:c@d>
#PARAM AllowSourceRoute
#
# The policy database:  (NOTE: See  'makendbm'  for its default suffixes!)
PARAM  policydb   @DBTYPE@  @MAILVAR@/db/smtp-policy
#
# HELO/EHLO-pattern	style-flags
#               [max loadavg]
#
localhost	    999	ftveR
some.host.domain    999	!NO EMAIL ACCEPTED FROM YOUR MACHINE
\[*\]		    999	ve
*		    999	veR
</verb></tscreen>


The PARAM keywords and values are:

<descrip>
<tag/<tt>maxsize nn</tt>/
	Maximum size in the number of bytes of the entire spool message
	containing both the transport envelope, and the actual message.
	That is, if the max-size is too low, and there are a lot of
	addresses, the message may entirely become undeliverable..

<tag/<tt>max-error-recipients nn</tt>/
	In case the message envelope is an error envelope (MAIL FROM:&lt;&gt;),
	the don't accept more than this many separate recipient addresses
	for it. The default value is 3, which should be enough for most cases.
	(Some SPAMs claim to be error messages, and then provide a huge
	 number of recipient addresses...)

<tag/<tt>MaxSameIpSource nn</tt>/
	(Effective only on daemon-mode server -- not on "-i", nor "-n" modes.)
	Sometimes some systems set up multiple parallel connections to same
	host  (qmail ones especially, not that ZMailer has entirely clean
	papers on this - at least up to 2.99.X series), we won't accept
	more than this many connections from the same IP source address
	open in parallel.  The default value for this limit is 10.

	The principal reason for this has been authors experience at nic.funet.fi,
	where some MS-Windows users have caused <bf>huge</bf> numbers
	of parallel connections to some services.  So huge, that the system
	did in fact run out of swap due to that, and caused all manner of
	other nasty things to occur too...  All this simply because some
	windows client had opened 800+ parallel sessions, and each server
	process consumed separate blocks of swap space...  To avoid the
	system to succumb under such an accidental denial-of-service attack
	at the overall system, this parallel limit was created.

<tag/<tt>ListenQueueSize nn</tt>/
	This relates on some newer systems where the <tt>listen(2)</tt> system call
	can define higher limits, than the traditional/original 5.  This
	limit tells how many nascent TCP streams we can have in SYN_RCVD
	state before we stop answering to incoming SYN packets requesting
	opening of a connection.

	There are entirely deliberate denial-of-service attacks based on
	flooding to some server many SYNS on which it can't send replies
	back (because the target machines don't have network connectivity,
	for example), and thus filling the back-queue of nascent sockets.
	This can also happen accidentally, as the connectivity in between
	the client host, and the server host may have a black hole into
	which the SYN-ACK packets disappear, and the client thus will not
	be able to get the TCP startup three-way handshake completed.

	Some newer systems can have this value upped to thousands to
	improve systems resiliency against malicious attacks, and most
	likely to provide complete immunity against the accidental
	"attack" by the failing network routing.

<tag/<tt>help 'string'</tt>/
	This one adds yet another string (no quotes are used) into those
	that are presented to the client when it asks for "HELP" in the
	SMTP session.

<tag/<tt>AllowSourceRoute</tt>/
	When this is present, possible incoming  &lt;&commat;aa,&commat;bb:cc&commat;dd&gt;  type of
	address is accepted in entirety without stripping it into &lt;cc&commat;dd&gt;.
	The default is that this is not present, and the RFC-821 source-
	route address is stripped into its basic form.

<tag/<tt>PolicyDB dbtype dbpath</tt>/
	This defines the database type, and file path prefix to the binary
	database containing policy processing information.  More of this
	below.  Actual binary database file names are formed by appending
	type specific suffixes to the path prefix.  For example NDBM
	database appends ".pag" and ".dir", while BSD-Btree appends only
	".db".  (And the latter has only one file, while the first has two.)
</descrip>

All lines that are not comments, nor start with uppercase keyword
"POLICY" are "EHLO-style patterns".



Delete to end of section?

If the <tt>MAILSHARE/<bf>smtpserver.conf</bf></tt> file exists it is read 
to configure two kinds of things:

<itemize>
<item> PARAM -entries
</itemize>

Allow server start-time parametrization of several things, including:

<itemize>
<item> system parameters
<item> help texts
<item> acceptance/rejection database definitions
<item>The style (<tt>-s</tt>) option
</itemize>

Behaviour is based on glob patterns matching the 
<bf>HELO/EHLO</bf> name given by a remote client. Lines 
beginning with a &num; or whitespace are ignored in the file, and 
all other lines must consist of two tokens: a shell-style (glob) 
pattern starting at the beginning of the line, whitespace, and a 
sequence of style flags. The first matching line is used. As a 
special case, the flags section may start with a ! character in 
which case the remainder of the line is a failure comment message 
to print at the client. This configuration capability is intended 
as a way to control misbehaving client software or mailers.


<sect2>Policy Based Filtering
<p>

The <tt>policy-builder.sh</tt> script bundles together a set of other
things before policy filter is ready for use:

<tscreen><verb>
		DB/smtp-policy.src			The boilerplate
		DB/localnames		('= _full_rights')
		DB/smtp-policy.relay	('= _full_rights')
		DB/smtp-policy.mx	('relaytargets +')
		DB/smtp-policy.spam	('= _bulk_mail')
</verb></tscreen>

At the moment, <tt>smtp-policy.spam</tt> source is retrieved with LYNX from
the URL: <tt>http://www.webeasy.com:8080/spam/spam_download_table</tt>
however it seems there are sites out there that are spam havens, and
that serve valid spam source/responce domains, which are not registered
at that database.

If you want, you can modify your boilerplate as well as your
installed <tt>policy-builder.sh</tt> script. Doing <tt>make install</tt> will
overwrite <tt>policy-builder.sh</tt>, but not <tt>smtp-policy.src</tt>.


Basically these various source files (if they exist) are used to
combine knowledge of valid users around us:

<descrip>
<tag/localnames/ Who we are -- ok for receiving ('_full_rights'
   is a bit too broad for that, though... because
   its value 'relaycustomer +' can allow anybody
   to use us for relaying by claiming some local
   identity at MAIL FROM:&lt;..&gt;.

<tag/smtp-policy.relay/ Who can use us as outbound relay,
   Use  [ip.number]/maskwidth  here for listing
   those senders (networks) we absolutely trust.
   We can set the "always_accept" flag at the
   source IP test, and never after.

<tag/smtp-policy.mx/ Who really are our MX clients.
   Use this when you really know them, and don't
   want just to trust that if recipient has MX
   to you, it would be ok...
   You can substitute this knowledge with a fuzzy
   feeling by using the `acceptifmx +' attribute in
   the generic boilerplate.

<tag/smtp-policy.spam/ Those users and domains that are
   absolutely a no-no for senders, or recipients
   no matter what earlier analysis has shown.
   (Except for those that we absolutely trust..)
</descrip>

<sect1>Router Configuration
<p>

The names (determined at compile-time) and interface specifications for the
routing and crossbar functions, are the only crucial ``magical'' things one
needs to contend with in a proper <em>router</em> configuration.  The syntax and
semantics of the configuration file's contents are dealt with in the
following subsection. The details of the two functions introduced here are
specified after that, once the necessary background information has been
given.

<em>Router</em> behavior is controlled by a configuration file read at 
startup. It is a <tt>zmsh(1)</tt> script that uses facilities provided 
built into the <em>router</em>. 

The configuration file looks like a Bourne Shell script at first glance.
There are minor syntax changes from standard <tt>sh</tt>, but the aim is to be as
close to the Bourne Shell language as is practical. The contents of the
file are compiled into a parse tree, which can then be interpreted by the
<em>router</em>.  The configuration file is usually self-contained, although an easy
mechanism exists to make use of external UNIX programs when so desired.
Together with a very flexible database lookup mechanism, functions, and
address manipulation based on token-matching regular expressions, the
configuration file language is an extremely flexible substrate to
accomplish its purpose. When the language is inadequate, or if speed
becomes an issue, it is possible to call built in (C coded) functions. The
interface to these functions is mostly identical to what a standalone
program would expect (modulo symbol name clashes and return values), to
ease migration of external programs to inclusion in the <em>router</em> process.

<sect2>Configuration File Programming Language
<p>

Whenever the <em>router</em> process starts, its first action is to read its
configuration file.  The configuration file is a text file which contains
statements interpreted immediately when the file is read.  Some statements
are functions, in which case the function is defined at that point in
reading the configuration file.  The purpose of the configuration file is
to provide a simple way to customize the behavior of the mailer, and this
is primarily achieved by defining the <tt>router</tt> and <tt>crossbar</tt> 
functions. For these to work properly, some initialization code and auxiliary
functions will usually be needed.

At first sight, a configuration file looks like a Bourne shell script.
The ideal is to duplicate the functionality, syntax, and to a large
degree the semantics, of a shell script.  Therefore, the configuration file
programming language is defined in terms of its deviation from standard
Bourne shell syntax and semantics.  The present differences are:

<itemize>
<item> No <tt>repeat</tt> statement.

<item> Functions are allowed, parameter lists are allowed. If not enough
 arguments are present in a function call to exhaust the parameter
 list, the so-far unbound parameter variables are bound to `' (the
 empty string) as local variables. For example, this is the identity
 address rewriting function:
     
<tscreen><verb>
          null (address) {
	  return $address         # surprise!
          }
</verb></tscreen>
<item> Multiple-value returns are allowed.  The <tt>return</tt> statement can be
 used to return a non-`' value from a function.  The following are all
 legal <tt>return</tt> statements:
     
<tscreen><verb>
          return
          return $address
          return $channel ${next_host} ${next_address}
</verb></tscreen>

<item> Variables are dynamically scoped, local variables are the 
ones in a function's parameter list and those declared with the 
``<tt>local</tt>'' statement. Only the first value of a multiple-value return may 
be assigned to a variable.  All values are strings, so no type information, 
checking, or declaration, is  necessary.
<item> Quoting is a bit stilted. All quotes (double-, single-, back-), must 
appear in matching pairs at the beginning and end of a word.  Single 
quotes are not stripped, double quotes cause the enclosed character 
sequence to be collected into a quoted-string RFC822 token.  For 
example, the statement:

<tscreen><verb>     
          foo `bar "`baz`"`
</verb></tscreen>
     
     is evaluated as <tt>(apply 'foo (apply 'bar (baz)))</tt>.
<item> The forms <tt>&dollar;{variable:=value}</tt>, 
<tt>&dollar;{variable:-value}</tt>, and
     <tt>&dollar;{variable:+value}</tt> are supported.  
<item> Patterns (in case labels) are evaluated once, the first time they are
     encountered.
<item> At the end of a case label, the sequentially next case labels of the
     same case statement will be tried for successful pattern matching (and
     the corresponding case label body executed). The only exceptions
     (apart from encountering a return statement) are:

     <tt>again</tt>     

          a function which retries the current case label for a match.

     <tt>break</tt>     

          continues execution after the current case statement.
<item> Various standard Bourne shell functions do not exist built in.

<item> The general form of function calls in the system is:
&dollar;(funcname arguments)
It returns a scalar or list object, and the result can be stored
into variables at will.

<item> Relations, and other database lookups are contructed as function calls
   where the relation name is the function name.  More about this later.
</itemize>

There are currently only three entry points (i.e. magic names known to the
<em>router</em> code) in the configuration file, namely the <tt>process</tt>, <tt>router</tt> and 
<tt>crossbar</tt> functions.

The <tt>process</tt> function is called with a file name as argument. 
The file is typically located in the <tt>&dollar;POSTOFFICE/router/</tt> 
directory. <tt>Process</tt> is a protocol switch function which uses the 
form of the file name to determine how to process different types of 
messages.

The <tt>router</tt> function is called with an address as argument, and returns a
triple of (channel, host, user) as three separate values, corresponding to
the channel the message should be sent out on (or, the router function can
also be called to check on who sent a message), the host or node name for
that channel (null if local delivery), and the address the receiving agent
should transmit to.

The <tt>crossbar</tt> function is in charge of rewriting envelope addresses,
selecting message header address munging type (a function to be called with
each message header address), and possibly doing per-message logging or
enforcing restrictions deemed necessary. It takes a sender-triple and a
receiver-triple as arguments (six parameters altogether). It returns the
new values for each element of the two triples, and in addition a function
name corresponding to the function to be used to rewrite header addresses
for the specific destination.  If the destination is to be ignored,
returning a null function name will accomplish this.

The <em>router</em> has several built in (C coded) functions.  Their calling
sequence and interface specification is exactly the same as for the
functions defined in the configuration file.  Some of these functions have
special semantics, and they fall into three classes, as follows:

Functions that are critical to the proper functioning of the configuration
file interpreter:

<descrip>
<tag/<tt>return</tt>/ returns its argument(s) as the value of a function call
<tag/<tt>again</tt>/ repeats the current case label
<tag/<tt>break</tt>/ exits a case statement
</descrip>

Functions that are necessary to complete the capabilities of the
interpreter:

<descrip>
<tag/<tt>relation</tt>/ defines a database to the database lookup mechanism
<tag/<tt>sh</tt>/ an internal function which runs its arguments as <tt>/bin/sh</tt> would
</descrip>

Non-critical but recommended functions:

<descrip>
<tag/<tt>getzenv</tt>/ retrieves global ZMailer configuration values
<tag/<tt>echo</tt>/ emulates <tt>/bin/echo</tt>
<tag/<tt>exit</tt>/ aborts the <em>router</em> with the specified status code
<tag/<tt>hostname</tt>/ internal function to get and set the system name
<tag/<tt>trace</tt>/ turns on selected debugging output
<tag/<tt>untrace</tt>/ turns off selected debugging output
<tag/<tt>[</tt>/ emulates a subset of <tt>/bin/test</tt>
	(a.k.a. <tt>/bin/&lsqb;</tt>) functionality    
</descrip>

The <tt>relation</tt> function is described in section
<ref id="Databases">,  Databases,
page <pageref id="Databases">.
Functions <tt>trace</tt> and <tt>untrace</tt> are described
in connection with debugging. 

See section <ref id="Logging_and_Statistics">, Logging and Statistics,
page <pageref id="Logging_and_Statistics">.
(This will probably change to Reference, Router, Debugging)

The <tt>hostname</tt> function requires some further explanation.
It is intended to emulate the BSD UNIX <tt>/bin/hostname</tt>
functionality, except that setting the hostname will only set
the <em>router's</em> idea of the hostname, not the system's.
Doing so will enable generation of `Message-Id' and `Received'
``trace'' headers on all messages processed by the <em>router</em>.
It is done this way since the <em>router</em> needs to know the official
domain name of the local host in order to properly generate these headers,
and this method is cleaner than reserving a magic variable for the purpose.
The <em>router</em> cannot assume the hostname reported by the system is
a properly qualified domain name, so the configuration file may generate
it using whichever method it chooses.
If the hostname indeed is a fully qualified domain name, then:

<tscreen>hostname "hostname"</tscreen>

will enable generation of trace headers.

Finally, note that a symbol can have both a function-value and a
string-value.  The string value is of course accessed using the &dollar; prefix
convention of the Bourne shell language.

To test the configuration or routing data, proceed as follows:

<tscreen><verb>
MAILBIN/router -i		(select interactive mode)
trace on			(turn tracing on)
router user@broken.address	(the address that gave you trouble)
router another@address		(and so on)
</verb></tscreen>

Old salts can use <tt>/usr/lib/sendmail -bt</tt> instead of <tt>router -i</tt>. Once satisfied that routing works,

<tscreen><verb>zmailer router</verb></tscreen>

will restart the <em>router</em>.

You can also run the <em>router</em> directly on a message.  Copy your message
to someplace other than the postoffice (<tt>/tmp</tt> is usually good), in a
numeric file name.  If the file name is <tt>123</tt>, you run

<tscreen><verb>MAILBIN/router 123</verb></tscreen>

this will create the file <tt>.123</tt> containing the control information
produced by the <em>router</em>.


<sect2>Databases<label id="Databases">
<p>

Many of the decisions and actions taken by configuration file code depend
on the specifics of the environment the MTA finds itself in.  So, not just
the facts that the local host is attached to (say) the UUCP network and a
Local Area Network are important, but it is also essential to know the specific
hosts that are reachable by this method.  Hardcoding large amounts of such
information into the configuration file is not practical.  It is also
undesirable to change what is really a program (the configuration file),
when the information (the data) changes.

The desirable solution to this data abstraction problem is to provide a way
for the configuration file programmer to manage such information externally
to ZMailer, and access it from within the <em>router</em>.  The logical way to do
this is to have an interface to externally maintained databases.  These
databases need not be terribly complicated; after all the simplest kind of
information needed is that a string is a member of some collection.  This
could simply correspond to finding that string as a word in a list of
words.

However, there are many ways to organize databases, and the necessary
interfaces cannot be known in advance.  The <em>router</em> therefore implements a
framework that allows flexible interfacing to databases, and easy extension
to cover new types of databases.

To use a database, two things are needed: the name of the database, and a
way of retrieving the data associated with a particular key from that
database.  In addition to this knowledge, the needs of an MTA do include
some special processing pertinent to its activities and the kind of keys to
be looked up.

Specifically, the result of the data lookup can take different forms: one
may be interested only in the existence of a datum, not its value, or one
may be looking up paths in a pathalias database and need to substitute the
proper thing in place of `<tt>%s</tt>' in the string returned from the database
lookup.  It should be possible to specify that this kind of postprocessing
should be carried out in association with a specific data access.
Similarly, there may be a need for search routines that depend on the
semantics of keys or the retrieved data.  These possibilities have all been
taken into consideration in the definition of a relation.  A relation maps
a key to a value obtained by applying the appropriate lookup and search
routines, and perhaps a postprocessing step, applied to a specified
database that has a specified access method.

The various attributes that define a relation are largely independent.
There will of course be dependencies due to the contents or other semantics
of a database.  In addition to the features mentioned, each relation may
optionally have associated with it a subtype, which is a string value used
to tell the lookup routine which table of several in a database
one is interested in.

There are no predefined relations in the <em>router</em>.  They must all be
specified in the configuration file, before first use.  This is done by
calling the special function <tt>relation</tt> with various options, as indicated
by the usage string printed by the <tt>relation</tt> function when called the wrong
way:

<tscreen><verb>
     Usage: relation -t dbtype [-f file -e# -s# -blnu -d driver] name
</verb></tscreen>

The `<tt>t</tt>' option specifies one of several predefined database types, each
with their specific lookup routine.  It determines a template for the set
of attributes associated with a particular relation.  The predefined
database types are:


<descrip>
<tag/<tt>bhash</tt>/ the database is in BSD DB HASH format.
<tag/<tt>bind</tt>/ the database is the BIND nameserver, accessed through the standard resolver routines.
<tag/<tt>btree</tt>/ the database is in BSD DB BTREE format.
<tag/<tt>dbm</tt>/ the database is in DBM format (strongly discouraged).
<tag/<tt>gdbm</tt>/ the database is in GNU GDBM format.
<tag/<tt>headers</tt>/ router internal database of various headers, and how they are
	to be treated.
<tag/<tt>hostsfile</tt>/ <tt>/etc/hosts</tt> lookup using <tt>gethostbyname()</tt>.
<tag/<tt>incore</tt>/ the database is a high-speed bundle of data kept entirely in the router process core memory.  This is for a short-term data storage, like handling duplicate detection.
<tag/<tt>ldap</tt>/ Mechanism for X.500 Directory access lookup with the "light-weight
	directory access protocol."
<tag/<tt>ndbm</tt>/ the database is in NDBM (new DBM) format.
<tag/<tt>ordered</tt>/ the database is a text file with key-datum pairs on each line, keys are looked up using a binary search in the sorted file.
<tag/<tt>selfmatch</tt>/ a special type that does translate the numerical address of format:
		12.34.56.78
	into binary form, and checks that it is (or is not) actually
	our own local IP addresses. This is used in address literal
	testing of addresses of type:
		localpart@[12.34.56.78]
<tag/<tt>unordered</tt>/ the database is a text file with key-datum pairs on each line, keys are looked up using a sequential search.
<tag/<tt>yp</tt>/ Sun SunOS 4.x YP (these days "NIS") interface library.
</descrip>

A subtype is specified by appending it to the database type name separated
by a slash.  For example, specifying <tt>bind/mx</tt> as the argument to the 
`<tt>t</tt>' option will store `<tt>mx</tt>' for reference by the access 
routines whenever a query to that relation is processed. The subtypes must 
therefore be recognized by either the database-specific access routines 
(for translation into some other form), or by the database interface itself.

For <tt>unordered</tt> and <tt>ordered</tt> database types, the datum 
corresponding to a particular key may be null.  This situation arises if 
the database is a simple list, with one key per line and nothing else.  
In this situation, the use of an appropriate post-processor option 
(e.g. `<tt>b</tt>') is recommended to be able to detect whether or not 
the lookup succeeded.

The `<tt>f</tt>' option specifies the name of the database.  This is typically a
path that either names the actual (and single) database file, or gives the
root path for a number of files comprising the database (e.g. <tt>foo</tt> may
refer to the NDBM files `<tt>foo.pag</tt>' and `<tt>foo.dir</tt>').  For the 
<tt>hostsfile</tt> type of database, the <tt>/etc/hosts</tt> file is the one 
used (and since the normal hosts file access routines do not allow specifying 
a different file, this cannot be overridden). The use of the <tt>dbm</tt> format 
is strongly discouraged, since a portable program can only have a single DBM 
database associated with it.

The `<tt>s</tt>' option specifies the size of the cache.  If this value 
is non-zero (by default it is 10), then an LRU cache of this size is 
maintained for previous queries to this relation, including both positive 
and negative results.

The `<tt>e</tt>' option specifies the cache data expiration time in seconds.

The `<tt>b</tt>' option asks that a postprocessor is applied to the database 
lookup result, so the empty string is returned from the relation query if the
database search failed, and the key itself it returned if the search
succeeded.  In the latter case, any retrieved data is discarded.  The
option letter is short for Boolean.

The `<tt>n</tt>' option asks that a postprocessor is applied to the database 
lookup result, so the key string is returned from the relation query if the
database search failed, and the retrieved datum string is returned if the
search succeeded.  The option letter is short for Non-Null.

The `<tt>l</tt>' option asks that all keys are converted to lowercase before 
lookup in the database.  This is mutually exclusive with the `<tt>u</tt>' 
option.

The `<tt>u</tt>' option asks that all keys are converted to uppercase before 
lookup in the database.  This is mutually exclusive with the `<tt>l</tt>' 
option.

The `<tt>d</tt>' option specifies a search routine.  Currently the only legal
argument to this option is <tt>pathalias</tt>, specifying a driver that searches
for the key using domain name lookup rules.

The final argument is not preceeded by an option letter.  It specifies the
name the relation is known under.  Note that it is quite possible for
different relations to use the same database.

Some sample relation definitions follow:

<tscreen><verb>
     if [ -f /etc/named.boot ]; then
         relation -nt bind/cname -s 100 canon  # T_CNAME canonicalize hostname
         relation -nt bind/uname uname         # T_UNAME UUCP name
         relation -bt bind/mx neighbour        # T_MX/T_WKS/T_A reachability
         relation -t bind/mp pathalias         # T_MP pathalias lookup
     else
         relation -nt hostsfile -s 100 canon   # canonicalize hostname
         relation -t unordered -f $MAILBIN/db/hosts.uucp uname
         relation -bt hostsfile neighbour
         relation -t unordered -f /dev/null pathalias
     fi
</verb></tscreen>

The above fragment defines a set of relations that can be accessed in the
same way, using the same names, independent of their actual definition.

<tscreen><verb>
     # We maintain an aliases database in the following format. Note: the
     # 'aliases' db name is magic to the internal alias expansion routines.
     if [ -f $MAILBIN/db/aliases.dat ]; then
         relation -t ndbm -f $MAILBIN/db/aliases aliases
     else
         relation -t ordered -f $MAILBIN/db/aliases.idx aliases
     fi
</verb></tscreen>

As the comment says, the relation name <tt>aliases</tt> has special significance
to the <em>router</em>.  Although the relation is not special in any other way (i.e.
it can be used in the normal fashion), the semantics of the data retrieved
are bound by assumptions in the aliasing mechanism.  These assumptions are
that key strings are local-name's, and the corresponding datum gives a byte
offset into another file (the root name of the aliases file, with a <tt>.dat</tt>
extention), which contains the actual addresses associated with that alias.
The reason for this indirection is that the number of addresses associated
with a particular alias can be very large, and this makes the traditional
simple database formats inadequate.  For example, quick lookup in a text
file is only practical if it is sorted and has a regular structure.  A
large number of addresses associated with an alias makes structuring a
problem.  The situation for DBM files and variations have problems too, due
to the intrinsic limits of the storage method.  The chosen indirection
scheme avoids such problems without loss of efficiency.

Finally, some miscellaneous definitions that illustrate various
possibilities:

<tscreen><verb>
     relation -t unordered -f /usr/lib/news/active -b newsgroup
     relation -t unordered -f /usr/lib/uucp/L.sys -b ldotsys
     relation -t ordered -f $MAILBIN/db/hosts.transport -d pathalias transport
</verb></tscreen>

Here, the first two illustrate convenient coincidences of format, and the
last definition shows what might be used if outgoing channel information is
maintained in a pathalias-format database (e.g. <tt>bar smtp!bar</tt> means to
send mail to <tt>bar</tt> via the SMTP channel).


<sect3>Using a Pathalias Database
<p>


Accessing route databases is a rather essential capability for a mailer.
At the University of Toronto, all hosts access a centrally stored database
through a slightly modified nameserver program.  If such a setup is not
practical at your site, other methods are available.  The most widespread
kind of route database is produced by the <tt>pathalias</tt> program.  It
generates key-value pairs of the forms:

<tscreen><verb>
     uunet                ai.toronto.edu!uunet!%s
     .css.gov             ai.toronto.edu!uunet!seismo!%s
</verb></tscreen>

which when queried about <tt>uunet</tt> and <tt>beno.css.gov</tt> correspond to 
the routes:

<tscreen><verb>
     ai.toronto.edu!uunet
     ai.toronto.edu!uunet!seismo!beno.css.gov
</verb></tscreen>

Notice that there are two basic forms of routes listed: routes to UUCP node
names and routes to subdomain gateways.  Depending on the type of route
query, the value returned from a pathalias database lookup needs to be
treated differently.  For now, this may be accomplished by a configuration
file relation definition and interface function as shown:

<tscreen><verb>
     relation -t ndbm -f $MAILBIN/uuDB -d pathalias padb
     
     # pathalias database lookup function
     padblookup (name, path) {             # path is a local variable
             path = ${$name:padb}
             case "$path" in
             ((.+)!)?([^!]+)!%s
                     if [ $3 == $name ]; then
                             path = $2!$3
                     else
                             path = $2!$3!$name
                     fi
                     ;;
             .*%s.*  echo illegal route in pathalias db: $path
                     ;;
             esac
             return $path
     }
</verb></tscreen>

This is actually a simplistic algorithm, but it does illustrate the method.
The lookup algorithm used when the `<tt>-d</tt>' flag is specified in the
relation definition command is rather simple; it doesn't test various case
combinations for the keys it tries.  Therefore, the keys in the pathalias
output data should probably be converted to a single case, and the `<tt>-l</tt>'
or `<tt>-u</tt>' flag given in the relation definition.


<sect2>Mailing Lists and &tilde;/.forward <label id="mailing_list_maintenance">
<p>

Mailing lists are implemented as files in the <tt>&dollar;MAILSHARE/lists/</tt> 
directory (or symlinks in there to files residing elsewere, though from a system
reliability standpoint it is better to have them in that directory,
and let users have symlinks to those files -- consider the NFS
with the user home directories in other machines...)

An alternate mechanism is to implement lists in the traditional <em>sendmail</em>
manner, however it means feeding the message to the scheduler, and
external program (<tt>/usr/lib/sendmail</tt>) before it comes back to the
<em>router</em>.

The list FILE must have protection 0664 or stricter, 0700 has invalid bits.
(ok, so the ``x"-bit is not used, but illegal it is, all the same.)
Preferrable protection is: 0600

The <tt>&dollar;MAILSHARE/lists/</tt> directory must be owned by root.
The directory containing the "aliases" file  (<tt>&dollar;MAILSHARE/db/</tt>) 
must be owned by root, and the aliases file must comply with above mentioned 
protections.

The owner of FILE gets FILE-owner, and FILE-request mails, <bf>unless any
of the limitations are breached</bf>.

If FILE has protection 666 (for example), the ZMailer internal function
"<tt>&dollar;(filepriv &dollar;filepath)</tt>" 
returns "<tt>&dollar;nobody</tt>" (userid of nobody), and  function
"<tt>&dollar;(uid2login &dollar;nobody)</tt>" fails, thus losing -owner, and 
-request features.

Also lists with filepriv ``nobody'' cannot be archived.

A mailing list is set up by creating a file in the 
<tt>&dollar;MAILVAR/lists/</tt> directory.
The file name is the lists' name (LIST) in all lowercase (case-
insensitive matching is done by converting to lowercase before
comparison).

The file contains a list of mail addresses (typically one per line)
which are parsed to pull out the destination addresses.  This means
the users' full names can be given just as in any valid RFC822 address.

The local account which owns the file will by default receive messages
sent to LIST-owner and LIST-request.  This can be explicitly overridden
in the aliases file.  Mail to the list will go out with LIST-owner as
the sender, so list bounce messages will return to the LIST-owner
address.  Archives of the list can be created by adding a file name
address (a local pathname starting with "/") to the LIST file.  The
archive file is written with the ownership of the owner of the LIST
file.  Forwarding the mailing list into a newsgroup
can be done using a mail to news script (two generations are provided
in utils/distribute and utils/mail2news).

<sect3>Security Considerations
<p>

A LIST file must not be world writable, while most likely it can be
group-writable.  The <tt>MAILVAR/lists/</tt> directory must also not be group
or world writable and must be owned by root or by the owner of the
LIST file.  Otherwise the file is declared insecure and all addresses
in the file get the least possible privilege associated (the ``nobody''
uid).  This can cause various things to break, for example mailing
list archival, or the -owner and -request features if ``nobody'' is
not a valid account.

There is a mechanism to override using the modes on a <tt>file/directory</tt>
as an indicator of its safeness.  Turning on the sticky bit on a file
or directory tells the mailer to treat it as if it was only owner
writable independent of its actual modes.  This allows <tt>MAILVAR/lists/</tt>
to be group or world writable and sticky-bitted if you want your general
user population to be able to create mailing lists.

<sect3>About Large Lists, and Memory Consumption
<p>

With old configuration scripts there used to be problems with list
expansion causing serious memory bloat.  <em>ZMailer-2.98-mea</em> did introduce
a working solution via the builtin  <tt>&dollar;(listexpand ..)</tt> function.

The rest of these notes apply to older config files using old style pipe
of <tt>&dollar;(listaddresses  < file | maprrouter ...)</tt>  where the  
maprrouter caused the actual memory bloat...

Internal list expansion (through the  <tt>&dollar;MAILVAR/lists/LISTNAME</tt> 
mechanism) is a sure way to expand <em>router</em> process memory usage.

You can decrease the memory requirement dramatically, if you can
feed all the addresses in the envelope, or via <tt>utils/listexpand.c</tt>
utility (alpha-test tool on 1-Sep-94) You don't need to worry about 
it unless your list is 100+ recipients, only then the memory usage starts 
to bloat seriously with the old-style in-core <tt>&dollar;(listaddress ...)</tt> 
expander.

Although more interesting and useful models exist, the mail forwarding
functionality of ZMailer has been designed to generally emulate the
interface and behaviour of <em>sendmail</em>.  The mechanisms that accomplish this
are likely to be generalized in a future version.

The file containing the actual aliasing data is automatically created by
the <em>router</em> when asked to reconstruct the aliases database.  It does this
based on a text file containing the alias definitions.  This text file,
which corresponds to the <em>sendmail</em> aliases file, consists of individual
alias definitions, possibly separated by blank lines or commentary.
Comments are introduced by a sharp sign (octothorp: `&num;') at any point where
a token might start (for example the beginning of a line, but not in the
middle of an address), and extend to the end of the line.  Each alias
definition has the exact syntax of an RFC822 message header, containing an
address-list, except for comments.  The header field name is the local-part
being aliased to the address-list that is the header value.

The fact that an alias definition follows the syntax for an RFC822 message
header, introduces an incompatibility with <em>sendmail</em>.  The string
<tt>:include:</tt> at the start of a local-part (a legacy of RFC733) has special
semantics. <em>Sendmail</em> would strip this prefix, and regard the rest of the
local-part as a path to a file containing a list of addresses to be
included in the alias expansion. Indeed, the <em>router</em> behaves in the same
manner, but because some of the characters in the prefix are RFC822
specials, the entire local-part must be quoted.  Thus, whereas <em>sendmail</em>
allowed:

<tscreen><verb>
     people: :include:/usr/lib/mail/lists/people
</verb></tscreen>
the proper syntax with ZMailer is:
<tscreen><verb>
     people: ":include:/usr/lib/mail/lists/people"
</verb></tscreen>

Like <em>sendmail</em>, if a local-part is not found in the aliases database, the
<em>router</em> also checks <tt>&tilde;local-part/.forward</tt> (if such exists) for 
any address expansion.  The <tt>.forward</tt> file format is also an RFC822 
address list, similar to what <em>sendmail</em> expects.

As special cases, a local-part starting with a pipe character (`<tt>|</tt>') is
treated as mail destined for a program (the rest of the local-part is any
valid argument to a <tt>sh -c</tt> command), and a local-part starting with a
slash character (`<tt>/</tt>') is treated as mail destined for the file named 
by the local-part.

General format:

<tscreen><verb>
	local-address-token:	"replacement address" ,
				"extension line w/ another addr"
	^^^^^^^^^^^^^^^^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	  "The Key"                "The Data"
</verb></tscreen>
Protection of the aliases database must be at least 0644.
Protection of the <tt>&dollar;MAILVAR/db/</tt> directory must be at least 03755.


The following processing is done for (replacement) local-parts
(local mail addresses):  Note that @'s are not allowed in any local-part.


If the local-part starts with ``|" assume it is a command specification:
<tscreen><verb>
		prog-pipe: "|/path/to/program -args"
</verb></tscreen>
If the local-part starts with ``/" assume it is a file pathname:
<tscreen><verb>
		file-path: "/path/to/file"
</verb></tscreen>
If the local-part starts with <tt>:include:</tt> the rest should be a file
pathname of a list of mail addresses.  They are substituted:
<tscreen><verb>
		included-list: ":include:/path/to/address/file"
</verb></tscreen>
After this point, all matches are case-insensitive by means of translating
the value to be looked up to lower-case, and then conducting a case-sensitive
lookup. <bf>All keys in aliases et.al. must be in lower case</bf>.
(The hash functions inside  <tt>ndbm/gdbm/db/dbm</tt>  are case sensitive, and 
as such, there is no way to avoid this requirement.)

<sect3>aliases.cf Logic
<p>

<itemize>
<item>If an aliases database exists and local-part is found in it, the list of
  addresses mapped to by the alias entry is substituted.

<item>If an mboxmap file exists and a mapping for the local-part is found in it,
  the mapping (a host!homedir!user value) determines the remote recipient
  (user@host) or recipient mailbox (<tt>homedir/../PObox/user</tt>) if host 
is local.

<item>If local-part is a login name and a readable <tt>.forward</tt> file 
exists in the home directory, the list of addresses it contains is substituted.

<item>If local-part is a file basename in the <tt>&dollar;MAILVAR/lists</tt> 
directory, the   list of addresses contained in the file is substituted, and 
the sender address set to local-part-owner.

<item>If local-part is of the form file-owner or file-request, where file is
 an entry in the <tt>&dollar;MAILVAR/lists</tt> directory, the account name 
of the owner of the file is substituted.   (File-owner identity and correct 
protections are important.)

<item>If the local-part is of format  ``user.name'',  it is actually mapped via
  separate   fullnamemap, and NEVER via <tt>&dollar;MAILVAR/db/aliases</tt>.

<item>If PUNTHOST is defined (in <tt>/etc/zmailer.conf</tt>) the address
  <tt>local-part@&dollar;PUNTHOST</tt> is substituted.  Note that in this case
  the mboxmap mechanism should be used to ensure local spool
  mailbox delivery for local users.
</itemize>

<sect1>Scheduler Configuration
<p>


The major action of the Scheduler is to periodically start up Transport
Agents and tell them what to do.  This is controlled by a table in a
configuration file that is read by the Scheduler when it starts.  

Any line starting with a `<tt>#</tt>' character is assumed to be a comment 
line, and is ignored, as are empty lines.  All other lines must follow a rigid
format. 

The scheduler configuration file consists of a set  of
clauses. Each clause is selected by the pattern it starts
with. The patterns  for  the  clauses	are  matched,  in
sequence, with the channel/host string for each recipient
address. When a clause pattern matches	an  address,  the
parameters set in the clause will be applied to the scheduler's 
processing of that address. If the clause specifies a command,  
the clause pattern matching sequence is terminated. This is a clause:

<tscreen><verb>
	    local/*   interval=10s
		      expiry=3h
		      # want 20 channel slots in case of blockage on one
		      maxchannel=20
		      # want 20 thread-ring slots
		      maxring=20
		      command="mailbox -8"
</verb></tscreen>

       A clause consists of:

<itemize>
<item>A selection pattern  (in  shell style) that  is
	      matched  against	the  channel/host  string  for an
	      address.

<item>0  or more  variable assignments or keywords
	      (described below).
</itemize>

If the selection pattern does not contain a '/', it is
assumed to be a channel pattern and the	host  pattern  is
assumed to be the wildcard '*'.

The components of a clause are separated by whitespace.
The pattern introducing a clause must start in the first
column of a line, and the variable assignments or keywords
inside a clause must not start in the first  column of a
line. This means a clause may be written both compactly
all on one line, or spread out with an assignment or keyword per line.

If the clause is empty (i.e., consists only of a pattern),
then the contents of the next non-empty	clause will be used.

The typical configuration file will contain the following clauses:
<itemize>
<item>a clause matching all addresses (using the pattern */*) that sets 
up default values.

<item>a  clause  matching  the  local delivery channel
	      (usually local).

<item>a clause matching the deferred	delivery  channel
	      (usually hold).

<item>a  clause  matching  the error reporting channel
	      (usually error).

<item>clauses specific to the other channels	known  by
	      the <em>router</em>, for example, smtp and uucp.
</itemize>

The  actual  names  of  these channels are completely 
controlled by the <em>router</em> configuration file.

Empty  lines,  and  lines   whose   first   non-whitespace
character is '&num;', are ignored.

Variable values may be unquoted words or values or double 
quoted strings.	 Intervals  (delta  time)  are	specified
using  a concatenation of: numbers suffixed with 's', 'm',
'h', or 'd' modifiers designating the number as a  second,
minute, hour, or day value.  For example: 1h5m20s.

The known variables and keywords, and their typical values
and semantics are:

<tt>interval (1m)</tt>
specifies the primary retry interval, which determines how frequently a 
transport agent should be scheduled for an address. The value is a delta
time specification. This value, and the retries value mentioned below, 
are combined to	determine the interval between each retry attempt.

<tt>idlemax</tt>
   When a transport agent runs out of jobs, they are moved
   to ``idle pool'', and if a transport agent spends more than idlemax
   time in there, it is terminated.

<tt>expiry (3d)</tt>
   specifies  the  maximum age of an address in the scheduler 
queue before  a repeatedly  deferred  address  is
   bounced with an expiration error.  The actual report is
   produced when all addresses have been processed.

<tt>retries (1 1 2 3 5 8 13 21 34)</tt> 
specifies the retry interval policy  of the scheduler 
for an address. The value must be a sequence of positive integers, these 
being multiples of the primary interval  before  a  retry is scheduled. 
The scheduler starts by going through the sequence as an  address  is 
repeatedly deferred. When the end of the sequence is reached, the scheduler 
will jump into the sequence at a random  spot and continue towards the end.  
This allows various retry strategies to be specified easily:

brute force (or "jackhammer"): <tt> retries=0 </tt>

constant primary interval: <tt> retries=1 </tt>

instant backoff: <tt> retries="1 50 50 50 50 50 50 50 50 50 50 50 50" </tt>

slow increasing (fibonacci) sequence: <tt> retries="1 1 2 3 5 8 13 21 34" </tt>

s-curve sequence: <tt> retries="1 1 2 3 5 10 20 25 28 29 30" </tt>

exponential sequence: <tt> retries="1 2 4 8 16 32 64 128 256" </tt>

        etc.

<tt>maxta (0)</tt> 
if retrying an address would cause the number of simultaneously 
active transport agents to exceed the specified  value, the retry is  
postponed. The check is repeated  frequently so  the address may be retried as
soon as possible after the  scheduled  retry interval. If the value is 0, 
a value of 1000 is used instead. Keep in mind that all  running  
transport  agents  will  keep open two <tt>pipe(2)</tt> file-handles, and thus 
system-wide  limits may force a lower maximum than 1000. On a system
with a maximum of 256 open files, this would most likely succeed at 120.

<tt>maxchannel (0)</tt>
   if retrying an address would cause the number of 
simultaneously  active  transport agents processing mail for
   the same channel to exceed  the  specified  value,  the
   retry  is  postponed.  The check is repeated frequently
   so the address may be retried as soon as possible after
   the  scheduled  retry  interval.   If the value is 0, a
   value of 1000 is used instead.

<tt>maxring (0)</tt>
   Recipients are groupped into ``threads'',  and  similar
   threads  are groupped into ``thread-rings'', where the same
   transport agent can be switched over from one recipient
   to another.  This defines how many transport agents can
   be running at any time at the ring.

<tt>skew (5)</tt>
   is the maximum number of retries before the retry  time
   is aligned to a standard boundary (seconds since epoch,
   modulo primary interval).  The lower this number (1  is
   lowest), the faster the alignment is done.  The purpose
   of this alignment is to ensure that eventually a single
   transport agent invokation will be able to process 
destination addresses that arrived randomly at the  scheduler.

<tt>user (root)</tt>
   is  the  user  id  of  a transport agent processing the
   address.  The value is either numeric  (a  uid)  or  an
   account name.

<tt>group (daemon)</tt>
   is  the  group  id  of a transport agent processing the
   address.  The value is either  numeric  (a  gid)  or a
   group name.

<tt>command (smtp -srl &dollar;LOGDIR/smtp &dollar;host)</tt>
   is  the command line used to start a transport agent to
   process the address. The program pathname is specified
   relative  to the  <tt>MAILBIN/ta</tt>  directory.   The  string
   "&dollar;channel" is replaced by the current matched  channel,
   and  "&dollar;host" is  replaced by the current matched host,
   from the destination address, and "&dollar;LOGDIR" substitutes
   ZENV variable LOGDIR value there.  It is strongly 
recommended that the &dollar;host is not to be used on a  command
   definition, as it limits the usability of the idled transporter.

<tt>bychannel</tt>
   is a keyword (with no associated value) that tells  the
   scheduler  that  the transport  agent specified in the
   command will only process  destination  addresses  that
   match  the  first  destination  channel  it encounters.
   This is automatically set when  the  string  "&dollar;channel"
   occurs  in the command, but may also be specified manu-
   ally by this keyword.  This is rarely used.

<tt>queueonly</tt>
   a clause with queueonly flag does not auto-start at the
   arrival  of  a  message,  instead it must be started by
   means of <tt>smtpserver(8)</tt> command ETRN thru an  SMTP  connection.

       For example, this is a complete configuration file:

<tscreen><verb>
	    # Default values
	    */*	      interval=1m expiry=3d retries="1 1 2 3 5 8 13 21 34"
		      maxring=0 maxta=0 skew=5 user=root group=daemon
	    # Boilerplate parameters for local delivery and service channels
	    local/*   interval=10s expiry=3h maxchannel=2 command=mailbox
	    error     interval=5m maxchannel=10 command=errormail
	    hold/*    interval=5m maxchannel=1 command=hold

	    # Miscellaneous channels supported by router configuration
	    smtp/*.toronto.edu
	    smtp/*.utoronto.ca maxchannel=10 maxring=2
		      command="smtp -srl $LOGDIR/smtp"
	    smtp      maxchannel=10 maxring=5
		      command="smtp -esrl $LOGDIR/smtp"

	    uucp/*    maxchannel=5 command="sm -c $channel uucp"
</verb></tscreen>

       The  first  clause  (*/*)  sets up default values for all
       addresses.  There is no command specification,  so  clause
       matching  will  continue  after address have picked up the
       parameters set here.

       The third clause (error) has an implicit host wildcard  of
       '*',  so  it  would  match  the same as specifying error/*
       would have.

The fifth clause (<tt>smtp/*.toronto.edu</tt>) has no further  
components so it selects the components of the following nonempty 
clause (the sixth).

Both the fifth and sixth clauses are specific  to  address
destinations  within the TORONTO.EDU and UTORONTO.CA 
organization (the two  are  parallel  domains).   At  most  10
deliveries to the smtp channel may be concurrently active,
and at most 2 for all possible hosts  within  TORONTO.EDU.
If &dollar;host  is  mentioned in the command specification, the
transport agent will only be told about the  message  control  
files that indicate SMTP delivery to a particular
host. The actual host is picked at random from the  current  
choices, to avoid systematic errors leading to a deadlock of any queue.







<sect1>sm Configuration
<p>

sm  is a ZMailer <em>sendmail</em> compatible transport agent which is usually only run
by the <tt>scheduler(8)</tt>, to deliver messages  by  invoking a
program with  facilities  and  in a way compatible with a
<em>sendmail</em> mailer. The sm program must be run with the same
current directory as the scheduler, namely <tt>POSTOFFICE/transport</tt>.

The program scans the message control files named on stdin
for addresses destined for the channel and/or the host
given on the command line. If any are found, all matching
addresses and messages are processed according to the
specifications for the mailer in the configuration file.

The exit status of a mailer should be one of the standard
values specified in <tt>&lt;sysexits.h&gt</tt>;. Of these, 
EX_OK indicates  successful  deliver,  and  EX_DATAERR,   EX_NOUSER,
EX_NOHOST,  EX_UNAVAILABLE,  and EX_NOPERM indicate permanent failure.  
All other exit codes will be treated  as a
temporary failure and the delivery will be retried.

Usage 

<tt>sm &lsqb; -8HQV &rsqb; &lsqb; -f configfile &rsqb; 
-c channel -h host mailer</tt>



<bf>Configuration</bf>

The configuration file <tt>MAILSHARE/sm.conf </tt> associates the 
mailer keyword  from
the command line with a specification of a delivery program.  
This is very similar to the way the definition of a
mailer in  <em>sendmail</em> requires flags, a program name, and a
command line specification.  These are in fact the  fields
of  the entries of the configuration file.  Lines starting
with whitespace or a `<tt>&num;</tt>' are ignored, and all  
others are assumed to follow this format:

<tscreen><verb>
       mailer	 flags	program			  argument list
</verb></tscreen>

       For example:

<tscreen><verb>
       local	 mS	sm/localm		  localm -r $g $u
       prog	 -	/bin/sh			  sh -c $u
       tty	 rs	/usr/local/to		  to $u
       uucp	 U	/usr/bin/uux		  uux - -r -a$g -gC $h!rmail ($u)
       usenet	 m	sm/usenet		  usenet $u
       ean	 mn	/local/lib/ean/gwsmean	  gwsmean -d $u
       test	 n	sm/test			  test $u
</verb></tscreen>

The mailer field extends from the beginning of the line to
the first whitespace.  It is used simply as a key index to
the configuration  file  contents.  Whitespace is used as
the field separator for all the fields.

The flags field contains  a  concatenation  of  one-letter
flags.  If no flags are desired, a `<tt>-</tt>' character should be
used to indicate presence of the field. All normal  <em>sendmail</em>  flags  are recognized, but the ones that do not make
sense in the context of ZMailer will  produce  an  error.
The flags that change the behaviour of sm are:

<descrip>
<tag/ <tt>b</tt>/ will activate BSMTP-type wrapping with a ``hidden-dot''
algorithm; e.g. quite ordinary SMTP stream, but in ``batch mode''.

<tag/ <tt>B</tt>/ The  first `<tt>B</tt>'  turns on similar BSMTP wrapping as
`<tt>b</tt>', but adds SIZE and, if the sm is  started  with
option `<tt>-8</tt>', also 8BITMIME options.  The second `<tt>B</tt>'
adds there also DSN (Delivery Status  Notification) parameters.

<tag/ <tt>E</tt>/ will prepend `&gt' to any message body line starting
       with `<tt>From </tt>'.

<tag/ <tt>f</tt>/ adds ``<tt>-f sender</tt>'' arguments to the delivery program.

<tag/ <tt>n</tt>/ will not prepend a From-space line (normal mailbox
separator line) to the message.

<tag/ <tt>r</tt>/ adds ``<tt>-r sender</tt>'' arguments to the delivery program.

<tag/ <tt>S</tt>/ will run the delivery program with the same real
and effective uid as the sm process.  If this  flag
is  not  set, the delivery program will be run with
the real uid of the sm process. This may be useful if sm is setuid.

<tag/ <tt>m</tt>/ informs sm that each instance of the delivery program  
can deliver to many destinations. This affects <bf>&dollar;u</bf> expansion 
in the argument list, see below.

<tag/ <tt>P</tt>/ prepends a Return-Path: header to the message.

<tag/ <tt>U</tt>/ will prepend a From-space line, with a ``remote from
myuucpname'' at the end, to the message. This is what is expected by remote 
<tt>rmail(1)</tt> programs for incoming UUCP mail.

<tag/ <tt>R</tt>/ use CRLF sequence as end-of-line sequence. Without
it, will use LF-only end-of-line sequence.

<tag/ <tt>X</tt>/ does SMTP-like ``hidden-dot'' algorithm  of doubling
all dots that are at the start of the line.

<tag/ <tt>7</tt>/ will strip (set to 0) the 8th bit of every character in the 
message.
</descrip>

The path field specifies the location of the delivery program. Relative 
pathnames are allowed and are relative to the <tt>MAILBIN/</tt> directory.

The arguments field extends to the end of the line. It
contains  whitespace separated  argv  parameters which may
contain one of the following sequences:

<descrip>
<tag/ <tt>&dollar;g</tt>/ which is replaced by the sender address.

<tag/ <tt>&dollar;h</tt>/ which is replaced by the destination host.

<tag/ <tt>&dollar;u</tt>/ which is replaced by the recipient address.  If the
<tt>-m</tt> mailer flag is set and there are several recipients for this 
message, the argument containing  the <tt>&dollar;u</tt> will be replicated 
as necessary for each recipient.
</descrip>




<!-- ref_smtp.sgml -->
<sect>Reference
<p>

This reference section tries to tell all the details of how each
subsystem parameter affects things, though perhaps without wide
explanations in every place. The usage examples and elaborations
are left (mostly) for the Administration part.

<sect1>SMTP-server
<p>

The ZMailer distribution contains an <em>SMTP</em> server program for the BSD socket
implementation of TCP/IP.  It is an asynchronous implementation, in that
address semantics are not checked in real time, nor are other (optional in
the <em>SMTP</em> standard) functions that require <em>router</em> functionality. The server
will run an RFC-821 syntax scanner for addresses and if things are ok, it 
says ``Yes yes, sure!'' to everything, and passes the information to
the <em>router</em> for verification.  The program may also be used in non-daemon
mode to unpack BSMTP format messages on the standard input stream.  For
compatibility with the <em>sendmail</em> variation on the <em>SMTP</em> protocol, it accepts
the <bf>VERB</bf> and <bf>ONEX</bf> commands as No-Ops. The <bf>VRFY</bf>, 
<bf>EXPN</bf>, <bf>HELP</bf>, and
<bf>TURN</bf> commands are presently unimplemented, as is the case for the
interactive <bf>SEND</bf>, <bf>SAML</bf>, and <bf>SOML</bf> commands.

This program implements the server side of the <em>SMTP</em> protocol as described in 
RFC821, and knows about the common extensions to the protocol expected by
<em>sendmail</em> and BSMTP clients. By default the program will kill the previous 
smtp-server daemon, if any, then detach and listen for <em>SMTP</em> connections. 
Incoming messages will be submitted for processing using the 
<tt>zmailer(3)</tt> interface to ZMailer. Nontrivial address checking is 
done asynchronously, although this behaviour can be changed by a command 
line option if you cannot afford to transfer data just to bounce it back. 
All checking is done by executing the <em>router(8)</em> program in 
interactive mode, and executing a well-known shell function with well-known 
parameters for each request.

<sect2>SMTP-server Runtime Parameters
<p>

<bf>Usage</bf>

<tt>smtpserver &lsqb; -46aginvBV &rsqb; &lsqb; -p port &rsqb; &lsqb; -l logfile &rsqb; &lsqb; -s &lsqb;ftveR&rsqb; &rsqb; &lsqb; -L maxloadaver &rsqb; &lsqb; 
-M SMTPmaxsize &rsqb; &lsqb; -P postoffice &rsqb; &lsqb; -R router &rsqb; 
&lsqb; -C cfgfile &rsqb;</tt>

<bf>Parameters</bf>

<descrip>
<tag/<tt>-4</tt>/ Explicitly use IPv4 type of socket even on machines that are capable to do IPv6 type of sockets.
<tag/<tt>-6</tt>/ Explicitly (try to) use IPv6 type of socket even if the machine does not support it. 
By default the server will try to use IPv6, if it has been compiled in an environment where it is present, 
but will fall back to IPv4 if the runtime system does not have IPv6.
<tag/<tt>-a</tt>/ Turn on RFC931/RFC1413 identification protocol, and log the information acquired with it to the 
submitted file.
<tag/<tt>-B</tt>/ Flags the email to arrive via BSMTP channel (via BITNET, for example).
<tag/<tt>-C cfgfile</tt>/ Specifies nonstandard configuration file location; the default is 
<tt>&dollar;MAILSHARE/smtpserver.conf</tt>.
<tag/<tt>-g</tt>/ The gullible option will make the program believe any information it is told 
(such as origin of a connection) without checking.
<tag/<tt>-i</tt>/ Runs the server interactively, which makes it usable for processing a batched 
<em>SMTP</em> stream (BSMTP) on <tt>stdin</tt>. With <tt>-v</tt> option this echoes incoming BSMTP to create more 
accurate faximile of BITNET BSMTP mailers.
<tag/<tt>-L maxloadaver</tt>/ The maximum load-average the system is under when we still accept email.
<tag/<tt>-l logfile</tt>/ Specifies a logfile and enables recording of incoming <em>SMTP</em> conversations.
<tag/<tt>-M SMTPmaxsize</tt>/ Defines the absolute maximum size we accept from incoming email. 
(Default: infinite) (This is a local policy issue.)
<tag/<tt>-n</tt>/ Indicates the program is being run from <em>inetd(8)</em>.
<tag/<tt>-P postoffice</tt>/ Specifies an alternate <tt>&dollar;POSTOFFICE</tt> directory.
<tag/<tt>-p port</tt>/ Specifies the TCP port to listen on instead of the default <em>SMTP</em> port, 25.
<tag/<tt>-R <em>router</em></tt>/ Specifies an alternate <em>router(8)</em> program to use for address verification.
<tag/<tt>-s</tt>/ Specifies the style of address verification to be performed. There are four independent commands 
that can invoke some kind of address verification, and four independent flags to control whether this should be done. 
They are:
<tt>f</tt> check <bf>MAIL FROM</bf> addresses
<tt>t</tt> check <bf>RCPT TO</bf> addresses
<tt>v</tt> check <bf>VRFY</bf> command argument
<tt>e</tt> check <bf>EXPN</bf> command argument
<tt>R</tt> require addresses to be of syntax: <tt>local@remote (strict 821)</tt>
The flags are concatenated to form the argument to the <tt>-s</tt> option. 
The default is <tt>ve</tt>.
<tag/<tt>-V</tt>/ prints a version message and exits.
</descrip>

<sect2>Configuration
<p>

If the <tt>&dollar;MAILSHARE/smtpserver.conf</tt> file exists it is read 
to configure two kinds of things. Specifically the following:

<itemize>
<item>The style (<tt>-s</tt>) options

Behaviour is based on glob patterns matching the <bf>HELO/EHLO</bf> name given by 
a remote client. Lines beginning with a &num; or whitespace are ignored in the file, 
and all other lines must consist of two tokens: a shell-style (glob) pattern starting 
at the beginning of the line, whitespace, and a sequence of style flags. The first 
matching line is used. As a special case, the flags section may start with a <tt>!</tt> 
character in which case the remainder of the line is a failure comment message to 
print at the client. This configuration capability is intended as a way to control 
misbehaving client software or mailers.
</itemize>

<itemize>
<item>PARAM -entries
</itemize>

Allow server start-time parametrization of several things, including:

<itemize>
<item> system parameters
<item> help texts
<item> acceptance/rejection database definitions
</itemize>

<descrip>
<tag/<tt>PARAM maxsize</tt>/ This is synonym to the start-time <tt>-M</tt> option.
<tag/<tt>PARAM max-error-recipients</tt>/ This defines how many recipients can be on a 
message whose source address is <bf>MAIL FROM:&lt;&gt</bf>. That is, is an error message.
<tag/<tt>PARAM TcpRcvBufferSize</tt>/ This sets <tt>setsockopt(SO_RCVBUF)</tt> value, 
in case the system default is not suitable.
<tag/<tt>PARAM policydb</tt>/ This defines <em>SMTP</em> input policy filtering/analysis 
database location. See the comments in the sample <tt>proto/db/smtp-policy.src</tt> file.
</descrip>

Here is a possible configuration file:

<tscreen><verb>
#PARAM maxsize          10000000  # Same as -M -option
#PARAM max-error-recipients   10  # More than this is propably SPAM! 
#PARAM TcpRcvBufferSize    32000  # Should not need to set!

# Our company contact info:
PARAM help ---------------------------------------------------
PARAM help  This mail-server is at Yoyodyne Propulsion Inc. 
PARAM help  Our telephone number is: +1-234-567-8900, and 
PARAM help  telefax number is: +1-234-567-8999
PARAM help  Our business-hours are Mon-Fri: 0800-1700 (Timezone: -0700) 
PARAM help
PARAM help  Questions regarding our email service should be sent via 
PARAM help  email to address  <postmaster@OURDOMAIN>
PARAM help  Reports about abuse are to be sent to: <abuse@OURDOMAIN> 
PARAM help ----------------------------------------------------
#
PARAM  accept-percent-kludge # "localpart" can contain '%' and '!' 
#PARAM reject-percent-kludge # "localpart" can't contain  --"-
#
# The policy database:
#     (NOTE: See 'makedb' for its default suffixes!)
#
PARAM  policydb btree /opt/mail/db/smtp-policy
#
# HELO pattern	style flags
#
*.mgmt.utoronto.ca	ftve
*.mgmt.toronto.edu	ftve
badguy.org		!Sorry, try later.
localhost		ve
*			-
</verb></tscreen>

<sect2>Policy Filtering Language
<p>

Policy based filter database boilerplate for smtp-server.

File:  <tt>&dollar;MAILVAR/db/smtp-policy.src</tt>

This file is compiled into an actual database using the command:

<tt>&dollar;MAILBIN/policy-builder.sh</tt>

<bf>Usage</bf>

<tt> key &lsqb;attribute value&rsqb;... &lsqb;= _tag&rsqb;</tt>
 
Where:

<tt>key</tt> is: 

<itemize>
<item>a domain name optionally preceded by a dot (.)
<item>``user@'' / ``user@domain'' names.
<item>an IP address expression in canonical &lsqb;nn.nn.nn.nn&rsqb;/prefix form. 
Unspecified bits must be 0. (Network IPv6 addresses containing IPv4-mapped 
addresses are translated into plain IPv4.)
<item>any arbitrary word referred as <tt>_tag</tt> at the right side
</itemize>
     <tt>_tag</tt> may be any key of this database

<tt>attribute</tt> and <tt>value</tt> are tokens. They are used by 
<tt>policytest()</tt> to make decisions.  Attribute names, and understood 
value tokens are:

<tscreen><verb>
	'='		'_any_token_with_starting_underscore' (aliasing)

	'rejectnet'	  { '+', '-' }
	'freezenet'	  { '+', '-' }
	'rejectsource'	  { '+', '-' }
	'freezesource'	  { '+', '-' }
	'relaycustomer'	  { '+', '-' }
	'relaycustnet'	  { '+', '-' }
	'relaytarget'	  { '+', '-' }
	'freeze'	  { '+', '-' }
	'senderokwithdns' { '+', '-' }
	'acceptifmx'	  { '+', '-' }
	'acceptifdns'	  { '+', '-' }
</verb></tscreen>

<sect3>Semantics
<p>

The <tt>policytest()</tt> function is called by smtp-server to check the client 
host, the sender's and recipients' addresses.  <tt>policytest()</tt> looks for 
the name and address of the client host as well as full and partial user address 
and domain part of sender and recipient addresses in this database.  The 
retrieved attributes are used to make decissions on accepting or rejecting 
the incoming mail.

If looking for `foo.bar.edu' and an exact match failed, the database looks for 
keys in sequence:  `.foo.bar.edu', `.bar.edu', `.edu', and `.'.

The order of entries in this file is not important.

When searching for an IP address the entry with the most common (leftside) bits
is returned. So you can have a &lsqb;0.0.0.0&rsqb;/0 entry what specifies the 
default addributes for all unlisted IP addresses. (Both IPv4 and IPv6)

 `=' is a special attribute.

The notation `= _tag' means ``See also at `_tag'". If <tt>server()</tt> doesn't 
find the requested attribute of the object, it will replace object name 
with `_tag' and restart the search.
 
Here is an example configuration, assuming the following decision 
chains of <tt>smtpserver/policytest.c</tt> routines:

Connection establishment:  (IP address tested)

<tscreen><verb>
  if (IP address of SMTP client has 'REJECTNET +' attribute) then
  any further conversation refused
   &lsqb;state->always_reject = 1; return REJECT;&rsqb;
  if (IP address of SMTP client has 'FREEZENET +' attribute) then
  we present happy face, but always put the messages into a freezer...
   &lsqb;state->always_freeze = 1; return FREEZE;&rsqb;
  if (IP address of SMTP client has 'RELAYCUSTNET +' attribute) then
   sender accepted, recipients not checked
   &lsqb;state->always_accept = 1; return ACCEPT;&rsqb;
  default: return ACCEPT
</verb></tscreen>

<bf>HELO/EHLO</bf> parameter string:

<tscreen><verb>
  if (state->always_reject == 1) return REJECT;
  if (state->always_freeze == 1) return FREEZE;
  if (state->always_accept == 1) return ACCEPT;
  if (HELO-name of SMTP client has 'REJECTNET +' attribute) then
   any further conversation refused
   &lsqb;state->always_reject = 1; return REJECT;&rsqb;
  if (HELO-name of SMTP client has 'FREEZENET +' attribute) then
   we present happy face, but always put the messages into a freezer..
   [state->always_freeze = 1; return FREEZE;]
  default: return ACCEPT
</verb></tscreen>

<bf>MAIL FROM</bf> address:

<tscreen><verb>
  set state->rcpt_nocheck  = 0;
  set state->sender_reject = 0;
  set state->sender_freeze = 0;
  if (state->always_reject == 1) return REJECT;
  if (state->always_freeze == 1) return FREEZE;
  if (state->always_accept == 1) return ACCEPT;
  if (sender's address has 'REJECTSOURCE +' attribute) then
   sender rejected, any further conversation refused
   [state->always_reject = 1; return REJECT;]
  if (sender's address has 'FREEZESOURCE +' attribute) then
   we accept with the happy face, but place it into a freezer
   [state->always_freeze = 1; return FREEZE;]
  when (sender's address is not in policy-db, continue with sender's domain)
  if (sender's domain is not in policy-db) then
    return ACCEPT
  if (sender's domain has 'REJECTSOURCE +' attribute) then
   sender rejected, any further conversation refused
   [state->sender_reject = 1; return REJECT;]
  if (sender's domain has 'FREEZESOURCE +' attribute) then
   we accept with the happy face, but place it into a freezer
   [state->sender_freeze = 1; return FREEZE;]
  if (sender's domain gas 'RELAYCUSTOMER +' attribute) then
   DANGER ! DANGER !
   We will accept all destination addresses for this MAIL FROM,
   except those that are explicitely blocked, of course..
   [state->rcpt_nocheck = 1; return ACCEPT;]
  if (sender's domain has 'SENDEROKWITHDNS +' attribute) then
    verify that is DNS data for the target domain.  If yes, return ACCEPT;
    if not, return "-100" (soft reject)
  if (sender's domain has 'SENDEROKWITHDNS -' attribute) then
    verify that is DNS data for the target domain.  If yes, return ACCEPT;
    if not, return REJECT
  else
    return ACCEPT
</verb></tscreen>

<bf>RCPT TO</bf> address:

<tscreen><verb>
  if (state->always_reject == 1) return REJECT;
  if (state->sender_reject == 1) return REJECT;
  if (state->always_freeze == 1) return FREEZE;
  if (state->sender_freeze == 1) return FREEZE;
  if (state->always_accept == 1) return ACCEPT;
  if (recipient address has 'RELAYTARGET +' attribute) then
    return ACCEPT
  if (recipient address has 'RELAYTARGET -' attribute) then
    return REJECT
  if (recipient address has 'FREEZE +' attribute) then
    we accept with the happy face, but place it into a freezer
    [status->sender_freeze = 1; return FREEZE;]
  if (recipient's domain has 'RELAYTARGET +' attribute) then
    return ACCEPT
  if (recipient's domain has 'RELAYTARGET -' attribute) then
    return REJECT
  if (recipient's domain has 'FREEZE +' attribute) then
    we accept with the happy face, but place it into a freezer
    [status->sender_freeze = 1; return FREEZE;]
  If (state->rcpt_nocheck  == 1) return ACCEPT;
  If (recipient's domain has 'ACCEPTIFMX +' attribute) then
    Verify that we are MX for the target domain.  If yes, return ACCEPT;
    If not, return "-100" (soft reject)
  If (recipient's domain has 'ACCEPTIFMX -' attribute) then
    Verify that we are MX for the target domain.  If yes, return ACCEPT;
    If not, return REJECT
  If (recipient's domain has 'ACCEPTIFDNS +' attribute) then
    Verify that we are MX for the target domain.  If yes, return ACCEPT;
    If not, return "-100" (soft reject)
  If (recipient's domain has 'ACCEPTIFDNS -' attribute) then
    Verify that we are MX for the target domain.  If yes, return ACCEPT;
    If not, return REJECT
  Else
    return ACCEPT
</verb></tscreen>

Default handling boilerplate. We are not relaying between off-site hosts, 
except when:

<tscreen><verb>
# -- 1st alternate: No MX target usage, no DNS existence verify
.			relaycustomer - relaytarget -
[0.0.0.0]/0		relaycustomer - relaytarget -
# -- 2nd alternate: No MX target usage, DNS existence verify
.			relaycustomer - relaytarget - senderokwithdns +
[0.0.0.0]/0		relaycustomer - relaytarget - senderokwithdns +
# -- 3rd alternate: MX relay trust, DNS existence verify
.			relaycustomer - acceptifmx + senderokwithdns +
[0.0.0.0]/0		relaycustomer - acceptifmx + senderokwithdns +
# -- 4th alternate: Sender & recipient DNS existence verify
.			senderokwithdns + acceptifdns +
[0.0.0.0]/0		senderokwithdns + acceptifdns +
</verb></tscreen>

These rules mean that locally accepted hostnames MUST be listed in
the database with the '<tt>relaytarget +</tt>' attribute.

Generally we refuse <em>SMTP</em> connections from host in private address space
and refuse mails to or from <tt>user@[nn.nn.nn.nn]</tt> if nn.nn.nn.nn is a
private IP address...

<tscreen><verb>
_private_address    rejectnet + rejectsource + relaycustomer - relaytarget -
[172.16.0.0]/12		= _private_address
[192.168.0.0]/16	= _private_address
[10.0.0.0]/8		= _private_address
</verb></tscreen>

...but hosts in the address range 192.168.16.0-192.168.17.255 may be
our <em>SMTP</em> clients.

<tscreen><verb>
[192.168.16.0]/23	rejectnet - = _private_address
</verb></tscreen>

Hosts of our organization can do anything...

<tscreen><verb>
_our_network		= _full_rights
_full_rights	rejectnet - relaycustnet + relaycustomer + relaytarget +

sztaki.hu		= _full_rights
.sztaki.hu		= _full_rights
192.84.225.0/24	= _our_network
192.84.226.0/23	= _our_network
192.84.228.0/23	= _our_network
</verb></tscreen>

...except that no use to relaying for dial-up hosts

<tscreen><verb>
.dial.sztaki.hu		relaytarget - = _full_rights
</verb></tscreen>

...and we have a misconfigured <em>SMTP</em> client somewhere

<tscreen><verb>
[192.84.225.1]/32		rejectnet + = _our_network
</verb></tscreen>

We are MX for some UUCP nodes;  The actual list of domains should
be retrieved from some listing, and inserted here, or generated from
a file into compatible format, and appended into the database.

<tscreen><verb>
.uucp.iif.hu		relaytarget +
</verb></tscreen>

Thanks, no bulk mails! Drop them when used as sources, also reject
when asked to send for them.

<tscreen><verb>
_bulk_mail		rejectsource + relaytarget -
</verb></tscreen>

The actual list of domains, and perhaps user addresses should
be retrieved from some active Anti-SPAM database

<tscreen><verb>
nobody.com		= _bulk_mail
.nobody.com		= _bulk_mail
nodomain.com		= _bulk_mail
.nodomain.com		= _bulk_mail
</verb></tscreen>

Some source users we reject always: (frequent spammers...)
(see comment above about Anti-SPAM databases)

<tscreen><verb>
friend@			= _bulk_mail
friends@		= _bulk_mail
</verb></tscreen>

<!-- ref_sendmail.sgml -->
<sect1>sendmail
<p>

This <em>sendmail</em> program is an emulation of the original
<em>sendmail</em> interface. It provides all the original options
that make sense to support in the context of ZMailer.
This is not intended to be the normal user interface to
<em>mail</em>, rather it is used by the old User Agent programs, e.g.,
<tt>mail(1)</tt>, to submit mail. This mechanism has been superseded
by the <tt>zmailer(3)</tt> library routines as the native
submission interface (Application Program Interface) for ZMailer.

The default action is to submit the RFC822 format mail
message	expected on <tt>stdin</tt> to the mailer, with the
addresses listed on the command line as recipients. If
there are no recipient addresses specified on the command
line, the mailer will infer them from the message header.
The sender is the account of the current <tt>userid</tt>, 
except for <tt>root</tt> where the preferred sender is the 
account of the current login session. The message terminates 
when a period is seen by itself on a line, or at end of file on
the input stream.

If the message submission fails immediately on the
<tt>mail_open(3)</tt>, the data on <tt>stdin</tt> will be 
appended to a <tt>dead.letter</tt> file in the submitters home directory.

<bf>Usage</bf>

<tt>
sendmail [-C configfile] [-EimqtUv] [-b[msdtip]]
[-Bbodytype] [-Nnotify] [-Rretmode]
[-Venvid] [-f address] [-F fullname]
[-r address] [-o[i|Qpostoffice]] [address ...]
</tt>

<bf>Parameters</bf>

<descrip>
<tag/ <tt>-bm</tt>/ asks <em>sendmail</em> to deliver mail, which it does anyway. 
This option has no effect.

<tag/ <tt>-bs</tt>/ will start an <em>SMTP</em> server reading from <tt>stdin</tt>. 
This causes the <em>smtpserver(8)</em> program to be executed.

<tag/ <tt>-bd</tt>/ starts the <em>router(8)</em> and <em>scheduler(8)</em> 
programs to emulate <em>sendmail</em>'s daemon mode. This is <bf>not</bf> a 
recommended method to start these programs, instead use <em>zmailer(1)</em>.

<tag/ <tt>-bt</tt>/ runs the <em>router(8)</em> in interactive mode for testing.

<tag/ <tt>-bi</tt>/ runs <em>newaliases(8)</em> to rebuild the alias file database.

<tag/ <tt>-bp</tt>/ runs <em>mailq(1)</em> to print the mail transport queue status.

<tag/ <tt>-C configfile</tt>/ specifies the <em>router(8)</em> configuration file.

<tag/ <tt>-E</tt>/ indicates the origin of this message is an insecure 
channel. This should be used when <em>sendmail</em> is used to submit 
messages coming in from outside the local machine, to avoid security 
problems during message processing. This flag ensures the message will 
have no privileges even if the current <tt>userid</tt> is ``trusted''.

<tag/ <tt>-f address</tt>/ specifies the sender address. This is the default 
originator address if there is no <tt>From:</tt> header in the message. 
It becomes the <tt>Sender:</tt> address otherwise. In either case if the 
current <tt>userid</tt> is not ``trusted'' by the mailer, it is free to 
ignore both this option and any header information to ensure properly 
authenticated originator information.

<tag/ <tt>-F fullname</tt>/ specifies the full name of the (local) sender.

<tag/ <tt>-i</tt>/ tells <em>sendmail</em> to not use a period (`.') on a line 
by itself as a message terminator, only the end of file will terminate the message.

<tag/ <tt>-m</tt>/ asks the mailer not to ignore the originator in the 
addressee list. This is default behaviour, so this option has no effect.

<tag/ <tt>-N notify</tt>/ sets Delivery-Status-Notification notify parameter 
to be: <tt>NEVER</tt>, or any combination of: <tt>SUCCESS</tt>, 
<tt>FAILURE</tt>, <tt>DELAY</tt>.

<tag/ <tt>-oi</tt>/ is like <tt>-i</tt>.

<tag/ <tt>-oQ postoffice</tt>/ specifies an alternate <tt>&dollar;POSTOFFICE/</tt> 
directory.

<tag/ <tt>-q</tt>/ asks for queue processing. This option has no effect.

<tag/ <tt>-R retmode</tt>/ sets Delivery-Status-Notification parameter to be 
either of: <tt>FULL</tt>, <tt>HDRS</tt>.

<tag/ <tt>-r address</tt>/ is like <tt>-f</tt>.

<tag/ <tt>-t</tt>/ scans header for recipient addresses if none are specified 
on the command line. This is also the default behaviour, so this option has no effect.

<tag/ <tt>-v</tt>/ will report the progress of the message after it has been 
submitted. The <em>sendmail</em> process will write verbose log information 
to the <tt>stderr</tt> stream until the <em>scheduler</em> deletes the message.

<tag/ <tt>-V envid</tt>/ sets Delivery-Status-Notification parameter <tt>ENVID</tt> 
to be any arbitrary &lsqb;<tt>xtext</tt>&rsqb; string.
</descrip>

<sect1>rmail
<p>

<em>rmail</em> is a program to process incoming UUCP mail.
<em>rmail</em> is usually invoked by a remote UUCP neighbour host's
mailer using a command line like:

<tscreen><verb>
uux - -r -asender -gC thishost!rmail (recipient1) (recipient2) ...
</verb></tscreen>

The end result is that the remote neighbour's <em>uuxqt(8)</em> runs
<em>rmail</em> on <tt>thishost</tt> with this command line:

<tscreen><verb>
rmail recipient1 recipient2 ...
</verb></tscreen>

In both cases, a UUCP format mail message is on the standard input.

The task of <em>rmail</em> is to transform the trace information in
the UUCP format message to the equivalent RFC822 trace
information, and to submit the message to the <em>zmailer(1)</em>
router with the appropriate envelope information.

The expected input format looks like:

<tscreen><verb>
From address3  date3 remote from host3
>From address2  date2 remote from host2
>From address1  date1 remote from host1
</verb></tscreen>

followed by the rest of the message. This is considered
equivalent to the following (as it might appear in a mailbox):

<tscreen><verb>
From host3!host2!host1!address1 date
Received: by host3 ... ; date3
Received: by host2 ... ; date2
Received: by host1 ... ; date1
</verb></tscreen>

In order for the mailer to process the incoming message
properly, <em>rmail</em> must be run by a <tt>userid</tt> which the
<em>router(1)</em> will accept forged mail from. This is normally
the UUCP account id.

<bf>Usage</bf>

<tt>
rmail [-d] [-h somewhere] recipient...
</tt>

<bf>Parameters</bf>

<descrip>
<tag/ <tt>-d</tt>/ turns on debugging output.

<tag/ <tt>-h somewhere</tt>/ will use the argument as the 
default remote UUCP host name to use if there is no <tt>remote from host</tt>
tag in the first From-space line in  the message.
The  default value for this is usually <tt>somewhere</tt> or
<tt>uunet</tt> (since uunet was a frequent purveyor of this
protocol violation).
</descrip>

<!-- ref_zmailer.sgml -->
<sect1>zmailer(3)
<p>

<bf>Usage</bf>
<tscreen><verb>
#include <stdio.h>
#include <zmailer.h>

FILE *mail_open(char *);

int mail_priority;

int mail_abort(FILE *);

int mail_close(FILE *);

int mail_close_alternate(FILE *mfp, char *where, char *suffix);

char *mail_alloc(unsigned int);

int mail_free(char *);

char *mail_host();

</verb></tscreen>

At linkage time use <tt>-lzmailer</tt>.

<tt>mail_open()</tt> will return a <tt>FILE *</tt> to a message
file that should be written to by the application. This
message file contains three parts: the message envelope,
the message header, and the message body. The exact format of
these components depend on the message protocol,
which must be specified as the parameter to <tt>mail_open()</tt>.
The choices are predetermined by the capabilities of the
mailer,	and are defined in the header file. The known
possibilities are:

<descrip>
<tag/ <tt>MSG_RFC822</tt>/ this is the only format supported 
by default by the mailer. The message headers and body in this format
are defined by the DARPA Request For Comments 822 and 1123. 
The message envelope syntax is similar to the message header syntax.

<tag/ <tt>MSG_FAX</tt>/ intended for fax transmissions.

<tag/ <tt>MSG_UUCP</tt>/ intended for old style UUCP format message headers

<tag/ <tt>MSG_X400</tt>/ intended for X.400(88) messages.
</descrip>

The <tt>mail_open()</tt> routine will look for <tt>&dollar;FULLNAME</tt> 
and <tt>&dollar;PRETTYLOGIN</tt> environment variables and translate 
them into message envelope data for use by the mailer if it generates 
a sender address header for the message.

Note that the return value from the <tt>mail_open()</tt> routine
corresponds to the return value of an <tt>fopen(3)</tt>, and similarly
the return values from <tt>mail_abort()</tt> and <tt>mail_close()</tt> 
correspond to the return value of <tt>fclose(3)</tt>.

The <tt>mail_priority</tt> variable has a default value of 0, 
and is used on scanning Zmailer configuration variable 
<tt>&dollar;ROUTERDIRS</tt>, which tells alternate router directories 
under the <tt>&dollar;POSTOFFICE</tt> directory. At value 0, 
<tt>&dollar;ROUTERDIRS</tt> variable is not used. At higher values, 
successive directory from <tt>&dollar;ROUTERDIRS</tt> is taken. 
See below about Z-Environment.

The <tt>mail_close_alternate(3)</tt> can be used to send currently
open message file to some alternate destination, and is
used at <em>smtpserver(8)</em> to send some quick-action requests
directly to the <em>scheduler(8)</em>.

The <tt>mail_alloc()</tt> and <tt>mail_free()</tt> routines are used 
to provide memory space for internal data structures. The versions
of these routines in the library simply call <tt>malloc(3)</tt> and
<tt>free(3)</tt> but an application may override them if desired.

Similarly the <tt>mail_host()</tt> routine is intended to return a
unique string for each host, by default the hostname, and
this too is intended to be overridden by an application
that may already have this information available in some form.

<bf>Envelope header lines</bf>

The message envelope headers are used to carry meta-information
about the message.  The goal is to carry transport-envelope 
information separate from message (RFC-822) headers, and body.
At first the message starts with a set of envelope headers 
(*-prefix denotes optional):

<tscreen><verb>
 *external \n
 *rcvdfrom %s@%s (%s) \n
 *bodytype %s \n
 *with %s \n
 *identinfo %s \n
</verb></tscreen>
 Either: <tt>from %lt;&percnt;s&gt; &bsol;n</tt> Or: <tt>channel error &bsol;n</tt>
<tscreen><verb>
 *envid %s \n
 *notaryret %s \n
</verb></tscreen>

Then for each recipient pairs of:
<tscreen><verb>
 *todsn [NOTIFY=...] [ORCPT=...] \n
 to <%s> \n
</verb></tscreen>

Just before the data starts, a magic entry:
<tscreen><verb>
 env-end \n
</verb></tscreen>

Then starts the message RFC-822 headers, and below it, the body.

<bf>Example</bf>

<tscreen><verb>
 ... set up signal handlers ...
 FILE *mfp = mail_open(MSG_RFC822,0);
 if (mfp != NULL) {
      ... output the mail message to mfp ...
 } else
      ... error handling for not being able to open the file ...
 if (some application processing went wrong
	   || we took an interrupt)
      (void) mail_abort(mfp);
 else if (mail_close(mfp) == EOF)
      ... error handling if something went wrong ...
</verb></tscreen>

<bf>Environment variables</bf>

<descrip>

<tag/ <tt>&dollar;FULLNAME</tt>/ variable defines textual fullname, 
for example: ``Sample User''

<tag/ <tt>&dollar;PRETTYLOGIN</tt>/ variable defines 
<tt>user&commat;node</tt> format of what user wants to claim as 
his/her own address (it must match those of mail router accepts.)
</descrip>

<bf>Z-environment variables</bf

<descrip>

<tag/ <tt>&dollar;POSTOFFICE</tt>/ defines the directory where all 
&dollar;POSTOFFICE functions are. 
Example: <tt>&dollar;POSTOFFICE=/var/spool/postoffice/</tt>

<tag/ <tt>&dollar;ROUTERDIRS</tt>/ defines a `:' separated list of alternate 
router directories. If these are defined at all, they must exist, 
if alternate queueing priority mechanism is desired to be used. 

Example: <tt>&dollar;ROUTERDIRS=router1:router2:router3:router4</tt>
</descrip>

<!-- ref_router.sgml -->
<sect1>Router
<p>

The <em>router</em> daemon makes all decisions affecting 
the processing of messages in ZMailer.

A mail message is submitted by placing it in a file in the
<tt>&dollar;POSTOFFICE/router/</tt> directory. The 
<em>router</em> frequently scans this directory for new 
files and will lock and process them as it finds them. 
The result is a message control file that gets linked into 
the <tt>&dollar;POSTOFFICE/scheduler/</tt> and 
<tt>&dollar;POSTOFFICE/transport/</tt> directories for use 
by the <em>scheduler(8)</em> in the next step of message 
processing. The original message file is then moved to the 
<tt>&dollar;POSTOFFICE/queue/</tt> directory. 

The <em>router</em>'s behaviour is controlled by a 
configuration file read at startup. It is really a 
<em>zmsh(1)</em> script that uses facilities provided 
builtin to the <em>router</em>. 

<bf>Usage</bf>

Invoking router without	any arguments will do nothing
(except	make it read its configuration file and promptly
exit). The normal startup method is to run the <em>zmailer(1)</em> 
script,	as in <tt>zmailer router</tt>. This will start the 
<em>router</em> as a daemon and	kill the previous 
incarnation of the <em>router</em>. 

<tscreen><verb>
router [ -diksSV ] [ -f configfile ] [ -n #routers ] [ -o 
zmshoptions ] [ -t traceflag ] [ -L logfile ] [ -P postof-
fice ] 
</verb></tscreen> 

<bf>Parameters</bf>

<descrip>
<tag/<tt>-d</tt>/ Detach and run as a daemon. 
<tag/<tt>-f configfile</tt>/ Overrides the default configuration 
file <tt>MAILSHARE/router.cf</tt>. 
<tag/<tt>-i</tt>/ Run interactively, presenting a <em>zmsh</em>  
session with the configuration file preloaded. 
<tag/<tt>-k</tt>/ Kill the currently running router by 
sending it a <tt>SIGTERM</tt> signal. 
<tag/<tt>-L logfile</tt>/ Overrides the default	log file location 
<tt>&dollar;LOGDIR/router/</tt>. 
<tag/<tt>-n &num;routers</tt>/ Starts the specified number of 
parallel router processes. The default is a single router process. 
<tag/<tt>-o zmshoptions</tt>/ Sets the option string passed on the 
internal <em>zmsh</em> invocation. The default is <tt>-O</tt>. 
Note that the leading `-' is mandatory. See <em>zmsh(1)</em> 
for the available options. 
<tag/<tt>-P postoffice</tt>/ Specifies an alternate 
<tt>&dollar;POSTOFFICE/</tt> directory. 
<tag/<tt>-S</tt>/ Can be used to turn off non-serious syslogging. 
<tag/<tt>-s</tt>/ Turns stability-flag off and on. Without this
flag, the search of new jobs will be done with (sometimes) 
timeconsuming care of organizing the job files into time order. 
<tag/<tt>-t traceflag</tt>/ Sets trace options, one per -t switch, 
even before the configuration file is loaded. This is otherwise 
equivalent to the builtin <tt>trace</tt> command. The currently 
known options are: <tt>assign, bind, compare, db, final, functions, 
matched, memory, on, regexp, resolv, rewrite, router, and sequencer</tt>. 
<tag/<tt>-V</tt>/ Print version message and run interactively. 
</descrip> 

To restart a <em>router</em> daemon: 
<tscreen><verb>
	 router -dk
</verb></tscreen>

To test an address, start up an interactive session: 
<tscreen><verb>
	 router -i
</verb></tscreen>

or if the ZMailer <em>sendmail(8)</em> is installed: 
<tscreen><verb>
	 sendmail -bt
</verb></tscreen>

Then just use the pre-defined functions.

<sect2>ZMSH Script Language
<p>

<em>zmsh</em> is an implementation of the Bourne shell 
suitable for use with the ZMailer <em>router(8)</em> as 
its configuration file language interpreter. It contains 
extensions that allow structured data (in the form of lists) 
to be manipulated. 

The shell supports three basic kinds of functions: Unix 
commands, user-defined functions, and builtin commands. 
The latter comes in two variations: normal functions which 
take string arguments and return a status code (much as an 
embedded Unix command would work), and list-manipulation 
functions which understand list arguments and can return 
list arguments.	The defined functions can take any form 
of argument and return any form of value (a status code, 
a string, or a list). 

Shell operations (pipes, backquote evaluation and substitution)	
will work between combinations of builtin functions, 
defined functions, and Unix commands.

The shell precompiles its input to a (possibly optimized) 
byte-code form, which is then interpreted as required. 
This means that the original form of the input is not kept 
around <tt>in-core</tt> for future reference. If the input 
is an included file, the shell will try to save the byte-code 
form in a <tt>.fc</tt> file associated with the input file. 
For example, if input is from <tt>file.cf</tt>, the shell 
will try to create <tt>fc/file.fc</tt> and then <tt>file.fc</tt>. 
These files will in turn be searched for and loaded 
(after a consistency check) whenever a <tt>.cf</tt> file is included. 

The effects of input and output redirections are predicted 
prior to the execution of a command and its I/O setup.

<bf>Usage</bf>

<tscreen><verb>
zmsh [ -CILOPRSYaefhinstuvx ] [ -c command ] [ script ...] 
</verb></tscreen>

<bf>Parameters</bf>

See the Debugging section for &lsqb;-CILOPRSY&rsqb; 
debugging options. 

<descrip>
<tag/<tt>-c command</tt>/ Run the given argument as a shell 
command script. 
<tag/<tt>-a</tt>/ Automatically export new or changed shell 
variables.  
<tag/<tt>-e</tt>/ Exit on non-zero status return of any command. 
<tag/<tt>-f</tt>/ Disables filename generation. 
<tag/<tt>-h</tt>/ Hash and cache the location of Unix commands. 
The option is set by default. 
<tag/<tt>-i</tt>/ This shell is interactive, meaning prompts 
are printed when ready for more input, <tt>SIGTERM</tt> signal 
is ignored, and the shell does not exit easily. This flag is 
automatically set if <tt>stdin</tt> and <tt>stderr</tt> are 
both attached to a <tt>tty</tt>. 
<tag/<tt>-n</tt>/ Read commands but do not execute them. 
<tag/<tt>-s</tt>/ Read commands from <tt>stdin</tt>. If there 
are non-option arguments to the shell, the first of these will 
be interpreted as a shell script to open on <tt>stdin</tt>, 
and the rest as arguments to the script. 
<tag/<tt>-t</tt>/ Exit after running one command. 
<tag/<tt>-u</tt>/ Unset variables produce an error on 
substitution. 
<tag/<tt>-v</tt>/ Print shell input as it is read. 
<tag/<tt>-x</tt>/ Print commands as they are executed. 
</descrip>

<sect2>Configuration Script Writing Rules
<p>Text to be inserted here.

<sect2>Debugging
<p>

The following debugging options are specific to the internal 
function of <em>zmsh</em>: 
<descrip>
<tag/<tt>-C</tt>/ Print code generation output onto 
<tt>stdout</tt>. If this option is doubled, the non-optimized 
code is printed out instead. 
<tag/<tt>-I</tt>/ Print runtime interpreter activity onto 
<tt>/dev/tty</tt>. 
<tag/<tt>-L</tt>/ Print lexer output onto <tt>stdout</tt>. 
<tag/<tt>-O</tt>/ Optimize the compiled script. If this 
option is doubled, the optimized code is also printed out. 
<tag/<tt>-P</tt>/ Print parser output (S/SL trace output) 
onto <tt>stdout</tt>. 
<tag/<tt>-R</tt>/ Print I/O actions onto <tt>/dev/tty</tt>. 
<tag/<tt>-S</tt>/ Print scanner output (token assembly) 
onto <tt>stdout</tt>. 
<tag/<tt>-Y</tt>/ Open <tt>/dev/tty</tt> for internal 
debugging use. 
</descrip>

<sect2>Security Issues
<p>Text to be inserted here.

<sect2>Internal Functions
<p>
This section describes the router internal functions.

<x>\vspace {2pt}</x>
<sect3>``colon''
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt><bf>:</bf></tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none
</descrip>

<x>\vspace {2pt}</x>
<sect3>``include''
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt><bf>.</bf> script</tt>
<tag/<bf>Return Values:</bf>/ status
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none
</descrip>

<x>\vspace {2pt}</x>
<sect3>``test''
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt><bf>&lsqb;</bf> &lcub;many 
parameters&rcub; &lsqb; 
&lcub;many parameters&rcub; &rsqb;</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>1</tt>/ True.
<tag/<tt>0</tt>/ False.
<tag/<tt>-1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ 
<itemize><item>File testing unary prefix functions:
<descrip><tag/<tt>-b file</tt>/ True if file exists and is block special.
<tag/<tt>-c file</tt>/ True if file exists and is character special.
<tag/<tt>-d file</tt>/ True if file exists and is a directory.
<tag/<tt>-f file</tt>/ True if file exists and is a regular file.
<tag/<tt>-g file</tt>/ True if file exists and is set-group-id.
<tag/<tt>-k file</tt>/ True if file has its ``sticky'' bit set.
<tag/<tt>-p file</tt>/ True if file exists and is a named pipe.
<tag/<tt>-r file</tt>/ True if file exists and is readable.
<tag/<tt>-s file</tt>/ True if file exists and has a size greater than zero.
<tag/<tt>-t &lsqb;fd&rsqb;</tt>/ True if <tt>fd</tt> is opened on a terminal. 
If <tt>fd</tt> is omitted, it defaults to 1 (standard output).
<tag/<tt>-u file</tt>/ True if file exists and its set-user-id bit is set.
<tag/<tt>-w file</tt>/ True if file exists and is writable.
<tag/<tt>-x file</tt>/ True if file exists and is executable.
</descrip>

<item>String testing binary functions:
<descrip><tag/<tt>str1 = str2</tt>/ True if the strings are equal.
<tag/<tt>str1 != str2</tt>/ True if the strings are not equal.
</descrip>

<item>Interget value testing binary functions:
<descrip>
<tag/<tt>iexpr -eq iexpr</tt>/ True if values are equal.
<tag/<tt>iexpr -ne iexpr</tt>/ True if values are not equal.
<tag/<tt>iexpr -gt iexpr</tt>/ True if value1 is greater than value2.
<tag/<tt>iexpr -ge iexpr</tt>/ True if value1 is greater or equal than value2.
<tag/<tt>iexpr -lt iexpr</tt>/ True if value1 is less than value2.
<tag/<tt>iexpr -le iexpr</tt>/ True if value1 is less or equal than value2.
</descrip>

<item>File comparison binary functions:
<descrip><tag/<tt>file1 -nt file2</tt>/ True if	file1's mtime is newer than file2's.
<tag/<tt>file1 -ot file2</tt>/ True if	file1's mtime is older than file2's.
<tag/<tt>file1 -ef file2</tt>/ True if both files have same inode, and device.
</descrip>

<item>Logical functions:
<descrip><tag/<tt>! expr</tt>/ Unary NOT
<tag/<tt>expr -a expr</tt>/ Binary AND
<tag/<tt>expr -o expr</tt>/ Binary OR
<tag/<tt>( expr )</tt>/ Parenthesis
</descrip>
</itemize>

<tag/<bf>Notes:</bf>/ This is basically the shell <tt>&lsqb;</tt> a.k.a. 
<tt>test</tt> program.
</descrip>

<x>\vspace {2pt}</x>
<sect3>attributes
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>attributes object-reference</tt>
<tag/<bf>Return Values:</bf>/ The property list symbol (4th) component 
of an address quad.
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none
</descrip>

<x>\vspace {2pt}</x>
<sect3>basename
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>basename pathname &lsqb; suffix &rsqb;</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ If a suffix is given and matches the filename, 
the suffix too is stripped from the filename.
<tag/<bf>Notes:</bf>/ Prints the base filename of the pathname.
</descrip>

<x>\vspace {2pt}</x>
<sect3>break
<p>
<x>\hrule</x>
<descrip>
<tag/<bf>Syntax:</bf>/ <tt>break</tt>
<tag/<bf>Return Values:</bf>/ <descrip><tag/<tt>1</tt>/ <p>
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none  
</descrip>

<x>\vspace {2pt}</x>
<sect3>builtin
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>builtin</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ 	<p>
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none  
</descrip>

<x>\vspace {2pt}</x>
<sect3>builtins
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>builtins</tt>
<tag/<bf>Return Values:</bf>/ none  
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ List builtin functions.
</descrip>

<x>\vspace {2pt}</x>
<sect3>car
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>car object-reference</tt>
<tag/<bf>Return Values:</bf>/ Pointer to copied lisp-object of 
object-reference's <tt>car</tt> operation.
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ This command is synonymous to the <tt>channel</tt> 
and <tt>first</tt> commands.  
</descrip>

<x>\vspace {2pt}</x>
<sect3>cd
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>cd &lsqb;directory&rsqb;</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <tt>cd</tt> successful.
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none  
</descrip>

<x>\vspace {2pt}</x>
<sect3>cdr
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>cdr object-reference</tt>
<tag/<bf>Return Values:</bf>/ Pointer to copied lisp-object of 
object-reference's <tt>cdr</tt> operation.
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ This command is synonymous to the <tt>rest</tt>
command.
</descrip>

<x>\vspace {2pt}</x>
<sect3>channel
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>channel object-reference</tt>
<tag/<bf>Return Values:</bf>/ The channel (1st) component of an address
quad.
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ The <tt>car</tt> and <tt>first</tt> commands are 
synonymous to this command. 
</descrip>

<x>\vspace {2pt}</x>
<sect3>continue
<p>
<x>\hrule</x>
<descrip>
<tag/<bf>Syntax:</bf>/ <tt>continue</tt>
<tag/<bf>Return Values:</bf>/ <descrip><tag/<tt>1</tt>/ <p>
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none  
</descrip>

<x>\vspace {2pt}</x>
<sect3>daemon
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>daemon</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ Starts the <em>router</em> running in daemon mode, 
scanning the <tt>&dollar;POSTOFFICE/router/</tt> directory every few 
seconds for message files to process. This function is invoked 
automatically by other code in the <em>router</em> program and has no 
other purpose.
</descrip>

<x>\vspace {2pt}</x>
<sect3>db
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>db &lcub; add|flush|owner|print|remove|toc &rcub; 
&lsqb;database &lsqb;key &lsqb;value&rsqb;&rsqb;&rsqb;</tt>

<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ 
<descrip><tag/<tt>a&lsqb;dd&rsqb;</tt>/ Add a <tt>key,value</tt> 
entry to the database, if possible.
<tag/<tt>f&lsqb;lush&rsqb;</tt>/ Remove all entries from the database, 
if possible.
<tag/<tt>o&lsqb;wner&rsqb;</tt>/ Print the account name of the owner 
of the database, if possible. This is usually determined by the 
files associated with the database.
<tag/<tt>p&lsqb;rint&rsqb;</tt>/ Print all entries of the database, 
if possible. 
<tag/<tt>r&lsqb;emove&rsqb;</tt>/ Remove a <tt>key</tt> entry 
from the database, if possible.
<tag/<tt>t&lsqb;oc&rsqb;</tt>/ Print a table of defined relations 
and their associated information. This table has five columns, 
in order: the name of the relation, its type and subtype, cache 
entries and maximum size, flags, and associated files. See the 
<tt>relation</tt> function for more information.
</descrip>
<tag/<bf>Notes:</bf>/  
<tscreen><verb>
	DBType        add    flush   owner   print   remove
	------        -------------------------------------
	incore        yes    yes     yes     yes     yes
	header        yes    yes     yes     yes     yes
	ordered       no     yes     yes     yes     no
	unordered     yes    yes     yes     yes     yes
	hostsfile     no     no      no      yes     no
	bind          no     no      no      no      no
	ndbm          yes    yes     yes     yes     yes
	gdbm          yes    yes     yes     yes     yes
	dbm           yes    yes     yes     yes     yes
	yp            no     no      yes     yes     no
	btree         yes    yes     yes     yes     yes
</verb></tscreen>
</descrip>

<x>\vspace {2pt}</x>
<sect3>dblookup
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>dblookup key</tt>
<tag/<bf>Return Values:</bf>/
<descrip>
<tag/<tt>cell</tt>/ <p>
<tag/<tt>NULL</tt>/ Error.	
</descrip>
<tag/<bf>Options:</bf>/ none
<tag/<bf>Notes:</bf>/ none
</descrip>

<x>\vspace {2pt}</x>
<sect3>echo
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>echo &lsqb;string-expressions&rsqb;</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>	
</descrip>
<tag/<bf>Options:</bf>/ 
<descrip><tag/<tt>-n</tt>/ Don't print newline at end of string.
</descrip>
<tag/<bf>Notes:</bf>/ The access function to the database facilities in the 
<em>router</em>.
</descrip>

<x>\vspace {2pt}</x>
<sect3>elements
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>elements lisp-object</tt>
<tag/<bf>Return Values:</bf>/ <tt>lisp-object</tt>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none
</descrip>

<x>\vspace {2pt}</x>
<sect3>envars
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>envars</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ Print internal variable tree.
</descrip>

<x>\vspace {2pt}</x>
<sect3>erraddron
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>erraddron &lsqb;file&rsqb;</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ Specifies a filename to append all address 
parsing error messages to. If there is no argument given, the 
logging is stopped. This is primarily for curious postmasters 
or other collectors of address trivia.
</descrip>

<x>\vspace {2pt}</x>
<sect3>eval
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>eval expression</tt>
<tag/<bf>Return Values:</bf>/ status
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none
</descrip>

<x>\vspace {2pt}</x>
<sect3>exit
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>exit</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ 	<p>
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf> /	Exit from the shell with exit code.
</descrip>

<x>\vspace {2pt}</x>
<sect3>export
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>export &lsqb;variable-name ...&rsqb;</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ Exports variable name(s). If no variables are given, 
export prints a list of which variables have been exported.
</descrip>

<x>\vspace {2pt}</x>
<sect3>filepriv
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>filepriv file &lsqb;uid&rsqb;</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ none
<tag/<bf>Notes:</bf>/ Prints the numeric user id of the least 
privileged account that can modify the specified file. This is 
determined by an approximation that pessimistically assumes that 
any file or directory writable by group or others is insecure, 
and optimistically assumes that it is enough to check a file and 
its parent directory instead of all the way to the filesystem root. 
The reason for the latter is that if grandparent directories are 
insecure, the system is likely to have just as bad potential 
problems as can be created by using mail to run processes with
forged powers (besides, doing the full check would be quite expensive).

If a second argument is given, it is the numeric user id to assume 
for the file. This means only the parent directory will be checked 
for nonwritability and for having the same (or a 0) uid.
</descrip>

<x>\vspace {2pt}</x>
<sect3>first
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>first object-reference</tt>
<tag/<bf>Return Values:</bf>/ Pointer to copied lisp-object of 
object-reference's <tt>car</tt> operation.
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ This command is synonymous to the <tt>car</tt> 
and <tt>channel</tt> commands.  
</descrip>

<x>\vspace {2pt}</x>
<sect3>gensym
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>gensym</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ Generates and prints a new symbol name in the 
sequence <tt>g0</tt> to <tt>gN</tt> every time it is called. The 
sequence is reset and any symbol values destroyed after the <em>router</em> 
has processed a message. This function is used to generate new symbols, to 
hold attached address property lists, during alias expansion.
</descrip>

<x>\vspace {2pt}</x>
<sect3>get
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>get property-list key</tt>
<tag/<bf>Return Values:</bf>/ <tt>property-list</tt>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ Returns a property list corresponding to key string.
</descrip>

<x>\vspace {2pt}</x>
<sect3>getopts
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>getopts optstring-name &lsqb;arguments 
...&rsqb;</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none  
</descrip>

<x>\vspace {2pt}</x>
<sect3>grind
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>grind lisp-object</tt>
<tag/<bf>Return Values:</bf>/ Pointer to list of <tt>varcell</tt>.
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none
</descrip>

<x>\vspace {2pt}</x>
<sect3>groupmembers
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>groupmembers groupname</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ Prints the accounts that are listed as 
members of a group in the system groups file, one per line.
Note that accounts with the same login group id, but that are 
not listed in the groups file, will not appear in this list.
</descrip>

<x>\vspace {2pt}</x>
<sect3>hash
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>hash &lsqb;-r&rsqb; &lsqb;command 
names&rsqb;</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
</descrip>
<tag/<bf>Options:</bf>/ 
<descrip><tag/<tt>-r</tt>/ Path is flushed.
</descrip>
<tag/<bf>Notes:</bf>/ none  
</descrip>

<x>\vspace {2pt}</x>
<sect3>homedirectory
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>homedirectory user</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ Prints the home directory of the specified 
user account.
</descrip>

<x>\vspace {2pt}</x>
<sect3>host
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>host object-reference</tt>
<tag/<bf>Return Values:</bf>/ The host (2nd) component of an 
address quad.
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none  
</descrip>

<x>\vspace {2pt}</x>
<sect3>hostname
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>hostname &lsqb;name&rsqb;</tt>
<tag/<bf>Return Values:</bf>/ <p>
<descrip><tag/<tt>0</tt>/ <p>
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ Sets the <em>router</em>'s idea of the
system hostname. Without an argument the name is retrieved from
the system and printed. The <em>router</em> has no preconceived 
notion of what the hostname is, so Message-Id and Received headers 
will only be generated if a hostname has been set using this function.
</descrip>

<x>\vspace {2pt}</x>
<sect3>last
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>last lisp-object</tt>
<tag/<bf>Return Values:</bf>/ Return a pointer to last cell of 
<tt>varcell</tt>'s list.
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none
</descrip>

<x>\vspace {2pt}</x>
<sect3>length
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>length lisp-object</tt>
<tag/<bf>Return Values:</bf>/ String of length of <tt>varcell</tt>'s 
parameter list.
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none  
</descrip>

<x>\vspace {2pt}</x>
<sect3>list
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>list lisp-object</tt>
<tag/<bf>Return Values:</bf>/ <tt>lisp-object</tt>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none
</descrip>

<x>\vspace {2pt}</x>
<sect3>listaddresses
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>listaddresses &lsqb;-e error-address&rsqb; 
&lsqb;-E errors-to-address&rsqb; &lsqb;-c comment&rsqb;</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ 
<descrip><tag/<tt>-e</tt>/ Any syntax errors at list parsing will cause a 
report to be mailed to the given address.
<tag/<tt>-E</tt>/ If an error occurs while messages are being delivered, 
the `errors-to-address' can be used to force error message destination 
elsewhere than to the default `sender' of the message.
<tag/<tt>-c</tt>/ A comment will be inserted in the error report.
</descrip>
<tag/<bf>Notes:</bf>/ Filters an RFC822 address list on standard input 
to produce one normal form (no non-address tokens) address per line on 
its output. This function can be used to parse the alias file or .forward 
files or similar.
</descrip>

<x>\vspace {2pt}</x>
<sect3>listexpand
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>listexpand &lsqb;-c comment&rsqb; 
&lsqb;-e error-address&rsqb; &lsqb;-E errors-to-address&rsqb; 
&dollar;attribute &dollar;localpart &dollar;origaddr &lt; listfile</tt>
<tag/<bf>Return Values:</bf>/ <tt>lisp-object</tt>
<tag/<bf>Options:</bf>/ 
<descrip><tag/<tt>-e error-address</tt>/ Any syntax errors at list 
parsing will cause a report to be mailed to the given address.
<tag/<tt>-E errors-to-address</tt>/ If an error occurs while messages 
are being delivered, the `errors-to-address' can be used to force error 
message destination elsewhere than to the default `sender' of the message.
<tag/<tt>-c comment</tt>/ A comment will be inserted in the error report.
</descrip>
<tag/<bf>Notes:</bf>/ Implements the most common pipeline where 
<tt>listaddresses</tt> was used with more efficient memory consumption 
handling. (That is, without variable duplicating <tt>setf</tt>'s.)
</descrip>

<x>\vspace {2pt}</x>
<sect3>login2uid
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>login2uid username</tt>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Notes:</bf>/ Prints the uid associated with the specified
account name, if any. A side-effect is to add the GECOS name field of 
the account to the <tt>fullname</tt> in-core database, to add the login 
name to uid mapping to the <tt>pwnam</tt> in-core database, and to add 
the uid to login name mapping to the <tt>pwuid</tt> in-core database.
</descrip>

<x>\vspace {2pt}</x>
<sect3>malcontents
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>malcontents</tt>
<tag/<bf>Return Values:</bf>/ none  
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none  
</descrip>

<x>\vspace {2pt}</x>
<sect3>printaliases
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>printaliases &lsqb;-v&rsqb; &lsqb;-o 
indexoutputfile&rsqb; file</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ 
<descrip><tag/<tt>-v</tt>/ Verbose.
<tag/<tt>-o indexoutputfile</tt>/ Each header line will also generate 
a <tt>header TAB byteoffset</tt> line in the indexfile.
<tag/<bf>Notes:</bf>/ Reads RFC822 syntax header lines from the specified
file, parses them assuming contents must be an address list, and sorts 
and prints the header lines with all addresses in normal form. Comments 
are allowed; they extend from the character `&num;' at the beginning of 
a line, or after an address, to the end of line. This function is used 
by the <em>newaliases(1)</em> program to generate the aliases database 
from a source file.
</descrip>
</descrip>

<x>\vspace {2pt}</x>
<sect3>process
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>process messagefile</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ The protocol switch function. It is called by
the <tt>daemon</tt> function to process a message found in the 
<tt>&dollar;POSTOFFICE/router/</tt> directory. This function will 
in turn call an internal protocol-specific function which knows the 
syntax and semantics of the message file. The current version knows 
about messages submitted using the <tt>MSG_RFC822</tt> parameter to 
<tt>mail_open(3)</tt>. For that case, the protocol function is called 
<tt>rfc822</tt>. <em>router</em> has a bit more complex directory 
semantics, than is stated above. See <tt>zmailer(3)</tt> for details. 
Although the <tt>process</tt> function is provided built in, it is 
usually overridden by a defined function in the <em>router</em> 
configuration file.
</descrip>

<x>\vspace {2pt}</x>
<sect3>read
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>read &lsqb;variable&rsqb;</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ Successful read.
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none  
</descrip>

<x>\vspace {2pt}</x>
<sect3>recase
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>recase &lsqb;-u | -l | -p&rsqb; 
string</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ 
<descrip><tag/<tt>-u</tt>/ Convert into uppercase.
<tag/<tt>-l</tt>/ Convert into lowercase.
<tag/<tt>-p</tt>/ Prettify.
</descrip>
<tag/<bf>Notes:</bf>/ A case-mapping function that prints the parameter 
string in either all-uppercase, all-lowercase, or capitalized (pretty).
</descrip>

<x>\vspace {2pt}</x>
<sect3>recipient
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>recipient</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>1</tt>/ Is a recipient address.
<tag/<tt>0</tt>/ Is not.
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ A boolean function that returns the value of 
the statement ``executing a header rewriting function and the address 
is a recipient address in a message header''.
</descrip>

<x>\vspace {2pt}</x>
<sect3>relation
<p>
<x>\hrule</x>
<descrip>
<tag/<bf>Syntax:</bf>/ <tt>relation -t dbtype&lsqb;,subtype&rsqb; 
&lsqb;-f file -e&num; -s&num; -bilmnu -d driver&rsqb; name</tt>

Options are listed below. <tt>name</tt> is the name of the relation
that is wanted to be created. Examples:
<tscreen><verb>
relation -t bind,mx mxhost
relation -t ordered -f $MAILVAR/db/routes routes
relation -t ordered -b -f /usr/lib/news/active.sorted newsgroups
</verb></tscreen>

<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
<tag/<tt>1..7</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ 
<descrip>
<tag/<tt>-t dbtype&lsqb;,subtype&rsqb;</tt>/ One of the known types 
of databases, currently: 
<descrip>
<tag/<tt>incore</tt>/ A database maintained in virtual memeory (using 
splay trees). This type should not be used for any database that must 
periodically be flushed, since all occupied memory can be freed.
<tag/<tt>header</tt>/ A database type used to store RFC822 header 
semantics information. It is unlikely to be used for anything else.
<tag/<tt>ordered</tt>/ A file with key-value pairs on every line, 
separated by whitespace, sorted by key. 
<tag/<tt>unordered</tt>/ A file with key-value pairs on every line, 
separated by whitespace. 
<tag/<tt>hostsfile</tt>/ <em>hosts(5)</em> file.
<tag/<tt>bind</tt>/ The BIND implementation of a Domain Name System 
resolver. The subtype for this type is the name of a Resource Record 
type in the <tt>IN</tt> class.
<tag/<tt>ndbm</tt>/ The new DBM library. The BSD4.4 has a thing called 
<tt>db</tt>, which is a different thing, but it can be used in place 
of <tt>ndbm</tt> via its interface library. (The <tt>BSD4.4-db</tt> 
does have only one database file, not two, like <tt>ndbm</tt> does.)
<tag/<tt>gdbm</tt>/ The GNU implementation of the new DBM library. 
<bf>Note:</bf> GDBM uses one file, which is named exactly as you 
parametrize it. This is unlike NDBM, which appends .dir and .pag to 
the supplied name!
<tag/<tt>dbm </tt>/ The old DBM library. There can be only one DBM 
open at the time, and this system keeps them all open all the time. 
Avoid if you can.
<tag/<tt>yp</tt>/ The Network Information Service from Sun Microsystems 
Inc. (Later renamed to be NIS, the still newer NIS+ is not supported).
<tag/<tt>btree</tt>/ <p>
</descrip>
<tag/<tt>-f file</tt>/ A file associated with the database, typically 
the file containing the data, or the basename of DBM files or something 
similarly relevant to the database access routine. 
<tag/<tt>-e&num;</tt>/ The default time-to-live on cached information. 
When the information has been in the cache for this many seconds, it 
is discarded. The default is 0. 
<tag/<tt>-s&num;</tt>/ Sets the cache size to the specified number. 
The default is usually 10, depending on the database type. 
<tag/<tt>-b</tt>/ If the key exists in the database, return the key 
as the value. 
<tag/<tt>-i</tt>/ If the key exists, its value is a byte offset into 
a file named by the subtype for this database. The value then becomes 
the concatenation of the data on the lines following that offset which 
start with whitespace. This is used for the aliases file. 
<tag/<tt>-l</tt>/ Map all keys to lowercase before searching.
<tag/<tt>-m</tt>/ Check for file content modification before every 
access. Reopen the file when a change is detected. This option is 
used when the <em>router</em> should discover changes to a database
underfoot so it need not be restarted to use new data. This is 
recommended on relations which use unordered, or ordered datasets 
(aliases, routes, ...), and especially if the system is configured 
to use <tt>mmap(2)</tt> facility. Updating such databases should 
preferably use <tt>mv</tt> command to move a new version of the 
database in place of the old one. 
<tag/<tt>-n</tt>/ If the key exists in the database and the value is 
null or list, return the key as value. Otherwise return the value 
retrieved, if any. 
<tag/<tt>-u</tt>/ Map all keys to uppercase before searching. 
<tag/<tt>-d driver</tt>/ Specifies a search driver that allows
searching for structured keys using special knowledge. The 
argument to this option must be a known driver. Currently the 
only known driver is <tt>pathalias</tt> which will search a
pathalias format database for an entry matching a domain name 
using the pathalias rules.
</descrip>
<tag/<bf>Notes:</bf>/ On systems with <tt>USE_MMAP</tt> the ordered 
and unordered databases are r/o mapped into memory, and for ordered 
case, a special line-index is generated for speeding up the binary 
search. (Makes less system calls that way.)
</descrip>

<x>\vspace {2pt}</x>
<sect3>rest
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>rest object-reference</tt>
<tag/<bf>Return Values:</bf>/ Pointer to copied lisp-object of 
object-reference's <tt>cdr</tt> operation.
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ This command is synonymous to the <tt>cdr</tt>
command.
</descrip>

<x>\vspace {2pt}</x>
<sect3>return
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>return lisp-object</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip>
<tag/<tt>lisp-object</tt>/ String contains a not ASCII digit character.	
(Returns a pointer to <tt>varcell</tt>'s string.)
<tag/<tt>statusp</tt>/ ASCII digit character. (Returns numeric value.)
<tag/<tt>NULL</tt>/ Invalid lisp-object.
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none  
</descrip>

<x>\vspace {2pt}</x>
<sect3>returns
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>returns lisp-object</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip>
<tag/<tt>string</tt>/ <p>
<tag/<tt>lisp-object</tt>/ <p>
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none
</descrip>

<x>\vspace {2pt}</x>
<sect3>rfc822
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>rfc822 messagefile</tt>
<tag/<bf>Return Values:</bf>/ <tt>status</tt>
<tag/<bf>Options:</bf>/ none
<tag/<bf>Notes:</bf>/ This function controls the parsing and 
processing of the message file in RFC822/976 format. It is 
called by the <tt>process</tt> function. 
</descrip>

<x>\vspace {2pt}</x>
<sect3>rfc822date
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>rfc822date</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
</descrip>
<tag/<bf>Options:</bf>/ none
<tag/<bf>Notes:</bf>/ Prints the current time in RFC822 format. 
</descrip>

<x>\vspace {2pt}</x>
<sect3>rfc822syntax
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>rfc822syntax address</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ This is a simple interface to the address 
parser. If the command line argument is a syntactically valid 
RFC822 address, this command is silent and returns 0 as exit 
status. If there is a parse error, a verbose error message is 
printed to <tt>stdout</tt> and the function returns a non-0 
exit status. 
</descrip>

<x>\vspace {2pt}</x>
<sect3>runas
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>runas user function 
&lsqb;arguments...&rsqb;</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ Changes the current effective user id 
of the <em>router</em> process to that given (which may be 
numeric or an account name), then runs the specified function 
with the specified arguments, then switches the effective 
user id of the process back (to root). 
</descrip>

<x>\vspace {2pt}</x>
<sect3>sender
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>sender</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>1</tt>/ Is a sender address.
<tag/<tt>0</tt>/ Is not.
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ A boolean function that returns the value of 
the statement ``executing a header rewriting function and the address 
is a sender address in a message header''. 
</descrip>

<x>\vspace {2pt}</x>
<sect3>set
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>set &lsqb;-a -e -f -h -n -t -u -v -x 
-L -C -P -S -k -&rsqb; variable</tt>

Without parameters <tt>set</tt> prints variable values.

<tag/<bf>Return Values:</bf>/ Pointer to copied structure of <tt>car</tt> 
operation.
<tag/<bf>Options:</bf>/ 
<descrip>
<tag/<tt>-a</tt>/ Automatically export changed variables.
<tag/<tt>-e</tt>/ Exit on error exit status of any command.
<tag/<tt>-f</tt>/ Disable filename generation (no globbing).
<tag/<tt>-h</tt>/ Hash program locations.
<tag/<tt>-n</tt>/ Read commands but do not execute them.
<tag/<tt>-t</tt>/ Read and execute one command only.
<tag/<tt>-u</tt>/ Unset variables are error on substitution.
<tag/<tt>-v</tt>/ Print shell input lines as they are read.
<tag/<tt>-x</tt>/ Print commands as they are executed.
<tag/<tt>-L</tt>/ Trace LEXER processing (sslWalker).
<tag/<tt>-C</tt>/ Print branch and emit inputs (sslWalker).
<tag/<tt>-P</tt>/ Trace execution (sslWalker).
<tag/<tt>-S</tt>/ Print input buffers when used (sslWalker). 
<tag/<tt>-k</tt>/ Not supported option.
<tag/<tt>-</tt>/ Do nothing.
</descrip>
<tag/<bf>Notes:</bf>/ none  
</descrip>

<x>\vspace {2pt}</x>
<sect3>setf
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>setf variable-reference 
&lsqb;new-value&rsqb;</tt>
<tag/<bf>Return Values:</bf>/ Pointer to original variable reference.
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ Replaces variable reference within a <tt>varcell</tt>.
</descrip>

<x>\vspace {2pt}</x>
<sect3>shift
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>shift &lsqb;number&rsqb;</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ Modifies caller's argument vector.
</descrip>

<x>\vspace {2pt}</x>
<sect3>sleep
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>sleep number</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/  none  
</descrip>

<x>\vspace {2pt}</x>
<sect3>squirrel
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>squirrel &lsqb;-&rsqb;event</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ 
<descrip>
<tag/<tt>-</tt>/ Set flag value to 0.
<tag/<tt>&lt;none></tt>/ Set flag value to 1. 

The events are: 
<itemize>
<item><tt>breakin</tt>
<item><tt>badheader</tt>
<item><tt>illheader</tt>
<item><tt>nochannel</tt>
<item><tt>nosender</tt>
</itemize>
</descrip>
<tag/<bf>Notes:</bf>/ Sets the kinds of events that cause a message 
to be copied into the <tt>&dollar;POSTOFFICE/postman/</tt> directory. 
Whether or not a `<tt>-</tt>' is necessary for an event depends on 
the current state of the event's flag. The usage message will 
indicate what to do to toggle the event flag. 
</descrip>

<x>\vspace {2pt}</x>
<sect3>stability
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>stability &lsqb;on | off&rsqb;</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ Determines whether the <em>router</em> will 
process incoming messages in arrival order (when on), or in random 
order determined by position in the router directory. The <em>router</em> 
will by default do the first queue scan in stable mode, and subsequent 
scans in unstable mode. The name of this command is the name for a 
similar characteristic of sorting algorithms. 
</descrip>

<x>\vspace {2pt}</x>
<sect3>test
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>test &lcub;many parameters&rcub; &lsqb; 
&lcub;many parameters&rcub; &rsqb;</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>1</tt>/ True.
<tag/<tt>0</tt>/ False.
<tag/<tt>-1</tt>/ Error.
</descrip>
<tag/<bf>Notes:</bf>/ This is basically the shell <tt>&lsqb;</tt> a.k.a. 
<tt>test</tt> program. See ``test'' command for the options.
</descrip>

<x>\vspace {2pt}</x>
<sect3>times
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>times </tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none  
</descrip>

<x>\vspace {2pt}</x>
<sect3>trace
<p>
<x>\hrule</x>
<descrip>
<tag/<bf>Syntax:</bf>/ <tt>trace key1 ... keyN</tt>

Enables tracing of the specified items. The valid keywords 
are listed in the options below. 
<tag/<bf>Return Values:</bf>/ 
<descrip>
<tag/<tt>0</tt>/ <p>
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ 
<descrip>
<tag/<tt>all</tt>/ Turns on all tracing options. You only 
do this to test the I/O capabilities of your system. 
<tag/<tt>assign</tt>/ Prints shell variable assignments. 
<tag/<tt>bind</tt>/ Prints various information from the 
code that calls the DNS resolver. 
<tag/<tt>compare</tt>/ Prints <tt>sift</tt> statement 
pattern-selector comparisons. 
<tag/<tt>db</tt>/ Prints database lookups, including cache 
search and update information. 
<tag/<tt>final</tt>/ Prints the message envelope information 
after processing each message. 
<tag/<tt>functions</tt>/ Prints shell function calls and 
return values, with nesting indicated by indentation. 
<tag/<tt>matched</tt>/ Prints <tt>sift</tt> statement 
pattern-selector matches. 
<tag/<tt>on</tt>/ Same as <tt>functions</tt>. 
<tag/<tt>regexp</tt>/ Prints regular expression matching execution. 
<tag/<tt>resolv</tt>/ Turns on the <tt>RES_DEBUG</tt> flag in the 
<tt>BIND</tt> resolver library, and prints various information 
from the code that calls the DNS resolver. 
<tag/<tt>rewrite</tt>/ Prints the tokenized addresses sent through 
the message header address rewriting functions. 
<tag/<tt>router</tt>/ Prints the tokenized addresses sent through 
the <tt>router</tt> function. 
<tag/<tt>sequencer</tt>/ Prints the procedural steps taken during 
message processing. 
<tag/<tt>memory</tt>/ Prints memory allocation information after 
each message. 
</descrip>
<tag/<bf>Notes:</bf>/ <p> 
</descrip>

<x>\vspace {2pt}</x>
<sect3>trap
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>trap &lsqb;&lsqb;script trap_nro&rsqb; 
...&rsqb;</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ If no parameters are given, <tt>trap</tt> prints all 
known traps.
</descrip>

<x>\vspace {2pt}</x>
<sect3>type
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>type &lsqb;command ...&rsqb;</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none
</descrip>

<x>\vspace {2pt}</x>
<sect3>uid2login
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>uid2login uid</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ Prints the first account name associated with 
a specified user id, if any, or <tt>uid&num;uid</tt> if no account 
exists with that user id. It has the same side-effects as the 
<tt>login2uid</tt> function. 
</descrip>

<x>\vspace {2pt}</x>
<sect3>umask
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>umask &lsqb;octal-number-mask&rsqb;</tt>
<tag/<bf>Return Values:</bf>/ Pointer to copied structure of <tt>car</tt> 
operation.
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ Without parameters default mask is 077.
</descrip>

<x>\vspace {2pt}</x>
<sect3>unset
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>unset &lsqb;variable ...&rsqb;</tt>
<tag/<bf>Return Values:</bf>/ 
<descrip><tag/<tt>0</tt>/ <p>
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none  
</descrip>

<x>\vspace {2pt}</x>
<sect3>untrace
<p>
<x>\hrule</x>
<descrip>
<tag/<bf>Syntax:</bf>/ <tt>untrace key1 ... keyN</tt>

Disables tracing of the specified items. 
<tag/<bf>Return Values:</bf>/ 
<descrip>
<tag/<tt>0</tt>/ <p>
<tag/<tt>1</tt>/ Error.
</descrip>
<tag/<bf>Options:</bf>/ See the <tt>trace</tt> function for 
valid keywords. 
<tag/<bf>Notes:</bf>/ <p>  
</descrip>

<x>\vspace {2pt}</x>
<sect3>user
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>user object-reference</tt>
<tag/<bf>Return Values:</bf>/ The next-address (3rd) component of 
and address quad.
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none
</descrip>

<x>\vspace {2pt}</x>
<sect3>wait
<p>
<x>\hrule</x>
<descrip><tag/<bf>Syntax:</bf>/ <tt>wait &lsqb;pid&rsqb;</tt>
<tag/<bf>Return Values:</bf>/ <tt>retcode</tt>
<tag/<bf>Options:</bf>/ none  
<tag/<bf>Notes:</bf>/ none
</descrip>

<!-- ref_scheduler.sgml -->
<sect1>Scheduler
<p>

The <em>scheduler</em> daemon manages the delivery processing of 
messages in ZMailer.

The <em>router</em> creates message control files in the
<tt>&dollar;POSTOFFICE/transport/</tt> directory. These refer to 
the original message files in the <tt>&dollar;POSTOFFICE/queue/</tt> 
directory.

The <em>scheduler</em> reads each message control file from
<tt>&dollar;POSTOFFICE/transport/</tt>, translates the contained 
message and destination information into internal data structures, 
and unlinks the message control file.

Based on scheduling, priority, and execution information read from a
configuration file, the <em>scheduler</em> arranges to execute 
Transport Agents relevant to the queued messages.

At the time scheduled for a particular transport agent invocation, the
<em>scheduler</em> will start a transport agent (or use one from idle-pool),
and tell it one by one which message control files to process.
When all the destination addresses in a message have been processed, the
<em>scheduler</em> performs error reporting tasks if any, and then deletes the
message control file in <tt>&dollar;POSTOFFICE/transport/</tt> and 
the original message file in <tt>&dollar;POSTOFFICE/queue/</tt>.

All message delivery is actually performed by Transport Agents, which
are declared in a configuration file for the <em>scheduler</em>.
Each transport agent is executed with the same current directory as the
<em>scheduler</em>. <em>scheduler-transporter</em> interaction protocol is
described later.

The standard output of each transport agent are destination address
delivery reports; either successful delivery, unsuccessful delivery, or
deferral of the address. Each report uses byte offsets in the message
control file to refer to the address. Reports may also include a comment
line which will be displayed in the reports of the <em>scheduler</em>.

Two types of reports are produced:
<enum>
<item>Error messages caused by unsuccessful delivery of a message
are appended to its message control file. Occasionally,
for example, when all addresses have been processed, the <em>scheduler</em>
generates an error message to the error return address of the message
(usually the original sender).  
<item>The <em>scheduler</em> binds itself to a well-known TCP/IP port
<tt>(MAILQ, TCP port 174)</tt> on startup.  Any connections to this port
are processed synchronously in the scheduler at points in the execution
where the state is internally consistent. The <em>scheduler</em>
simply dumps its internal state in a terse format to the TCP stream.
It is expected that the client program will reconstruct the data structures
sufficiently to give a user a good idea of what the scheduler thinks the
world looks like. The <em>mailq (1)</em> program serves this purpose.
</enum>

<bf>Usage</bf>

Invoking <em>scheduler</em> without any parameter will start it as a daemon.

<tscreen><verb>
scheduler [-divFHQSVW] [-f configfile] [-E newentsmax] [-Llogfile] [-lstatisticslog]
[-Ntranspmaxfno] [-P postoffice] [-R maxforkfreq] [-q rendezvous]
</verb></tscreen>

<bf>Parameters</bf>

<descrip>
<tag/<tt>-d</tt>/ run as a daemon, usually used after -v to log daemon activity 
in great detail.
<tag/<tt>-E newentsmax</tt>/ when globbing new tasks from the directory, pick 
only first <tt>newentsmax</tt> of them, and leave rest for a new scan run.
<tag/<tt>-f configfile</tt>/ overrides the default configuration file 
<tt>MAILSHARE/scheduler.cf</tt>.
<tag/<tt>-F</tt>/ Freeze -- don't actually run anything, just do queue scanning.
(For debug purposes..)
<tag/<tt>-H -HH</tt>/ Use multi-level hashing at the spool directories.
This will efficiently reduce the lengths of the scans at the directories
to find some arbitary file in them.
One <tt>H</tt> means <tt>single level hashing</tt>, two <tt>HH</tt> mean
<tt>dual level hashing</tt>. <tt>Hash</tt> is directory which name is
single upper case alphabet (A-Z).
<tag/<tt>-i</tt>/ run interactively, i.e., not as a daemon.
<tag/<tt>-L logfile</tt>/ overrides the default log file location 
<tt>LOGDIR/scheduler</tt>.
<tag/<tt>-l statisticslog</tt>/ starts the appending of delivery statistics 
information (ASCII form) into given file.  No default value.
<tag/<tt>-N transmaxfno</tt>/ sets how many filehandles are allocated for the 
<em>scheduler</em>'s started children (if the system has adjustable resources.)
<tag/<tt>-P postoffice</tt>/ specifies an alternate <tt>POSTOFFICE/</tt> directory.
<tag/<tt>-q rendezvous</tt>/ the rendezvous between machines without TCP/IP networking, 
<tag/<tt>-Q</tt>/ The `<tt>Q</tt>'-mode, don't output the old style data into the queue 
querier, only the new-style one.
<tag/<tt>-S</tt>/ Synchronous startup mode, scans all jobs at the directory before 
starting even the first transporter.
<tag/<tt>-v</tt>/ Verbose logging in interactive mode -- for debug uses.
<tag/<tt>-V</tt>/ Print version, and exit
<tag/<tt>-W</tt>/ Another option for debugging, delay the start of the verbose logging
until after all jobs have been scanned in, and it is time to start the transporters. 
<em>scheduler</em> and <em>mailq (1)</em> is done using a well-known named pipe. 
This option overrides the default location for this special file, either 
<tt>&dollar;RENDEZVOUS</tt> or <tt>/usr/tmp/.mailq.text</tt>.
</descrip>


<sect2>Configuration Language
<p>
The <em>scheduler</em> configuration file consists of a set of clauses. 

<sect3>Clause selection
<p>Each clause is selected by
the pattern it starts with. The patterns for the clauses are matched,
in sequence, with the <tt>channel/host</tt> string for each recipient
address. When a clause pattern matches an address, the parameters set in
the clause will be applied to the <em>scheduler</em>'s processing of 
that address. If the clause specifies a command, the clause pattern 
matching sequence is terminated. This is a clause:
<tscreen><verb>
local/*	interval=10s
	expiry=3h
	# want 20 channel slots in case of blockage on one
	maxchannel=20
	# want 20 thread-ring slots
	maxring=20
	command="mailbox -8"
</verb></tscreen>

A clause consists of:
<itemize>
<item>A selection pattern (in shell style) that is matched against the
<tt>channel/host</tt> string for an address.
<item>0 or more variable assignments or keywords (described below).
</itemize>
If the selection pattern does not contain a <tt>/</tt>, it is assumed to
be a channel pattern and the host pattern is assumed to be the wildcard
<tt>*</tt>.

<sect3>Clause components
<p>
The components of a clause are separated by whitespace. The pattern
introducing a clause must start in the first column of a line, and the
variable assignments or keywords inside a clause must not start in the
first column of a line. This means a clause may be written both compactly
all on one line, or spread out with an assignment or keyword per line.

If the clause is empty (i.e., consists only of a pattern), then the
contents of the next non-empty clause will be used.

The typical configuration file will contain the following clauses:
<itemize>
<item>a clause matching all addresses (using the pattern <tt>*/*</tt>)
that sets up default values.
<item>a clause matching the local delivery channel (usually <tt>local</tt>).
<item>a clause matching the deferred delivery channel (usually <tt>hold</tt>).
<item>a clause matching the error reporting channel (usually <tt>error</tt>).
<item>clauses specific to the other channels known by the <em>router</em>,
for example, <tt>smtp</tt> and <tt>uucp</tt>.
</itemize>
The actual names of these channels are completely controlled by the
<em>router</em> configuration file.

Empty lines, and lines whose first non-whitespace character is <tt>&num</tt>,
are ignored.

Variable values may be unquoted words or values or doublequoted strings.
Intervals (delta time) are specified using a concatenation of: numbers
suffixed with `s', `m', `h', or `d' modifiers designating the number as
a second, minute, hour, or day value. For example: <tt>1h5m20s</tt>.

<sect3>Variables and keywords
<p>
The known variables and keywords, and their typical values and semantics are:
<descrip>
<tag/<tt>interval (1m)</tt>/ specifies the primary retry interval, which 
determines how frequently a transport agent should be scheduled for an address. 
The value is a delta time specification. This value, and the <tt>retries</tt>
value mentioned below, are combined to determine the interval between
each retry attempt.

<tag/<tt>idlemax (3x interval)</tt>/ When a transport agent runs out of jobs, 
they are moved to <tt>idle pool</tt>, and if a TA spends more than 
<tt>idlemax</tt> time in there, it is terminated.

<tag/<tt>expiry (3d)</tt>/ specifies the maximum age of an address in the 
<em>scheduler</em> queue before a repeatedly deferred address is bounced 
with an expiration error. The actual report is produced when all addresses 
have been processed.

<tag/<tt>retries (1 1 2 3 5 8 13 21 34)</tt>/ specifies the retry interval 
policy of the <em>scheduler</em> for an address. The value must be a sequence 
of positive integers, these being multiples of the primary interval before a 
retry is scheduled. The <em>scheduler</em> starts by going through the 
sequence as an address is repeatedly deferred. When the end of the sequence 
is reached, the <em>scheduler</em> will jump into the sequence at a random 
spot and continue towards the end. This allows various retry strategies to be 
specified easily:
<itemize>
<item>brute force (or "jackhammer"):
<tscreen><verb>
retries=0
</verb></tscreen>
<item>constant primary interval:
<tscreen><verb>
retries=1
</verb></tscreen>
<item>instant backoff:
<tscreen><verb>
retries="1 50 50 50 50 50 50 50 50 50 50 50 50"
</verb></tscreen>
<item>slow increasing (fibonacci) sequence:
<tscreen><verb>
retries="1 1 2 3 5 8 13 21 34"
</verb></tscreen>
<item>s-curve sequence:
<tscreen><verb>
retries="1 1 2 3 5 10 20 25 28 29 30"
</verb></tscreen>
<item>exponential sequence:
<tscreen><verb>
retries="1 2 4 8 16 32 64 128 256"
</verb></tscreen>
<item>etc.
</itemize>

<tag/<tt>maxta (0)</tt>/ if retrying an address would cause the number of 
simultaneously active transport agents to exceed the specified value, 
the retry is postponed. The check is repeated frequently so the address 
may be retried as soon as possible after the scheduled retry interval. 
If the value is 0, a value of 1000 is used instead. Keep in mind that all 
running transport agents will keep open <bf>two</bf> <tt>pipe (2)</tt> 
file-handle, and thus system-wide limits may force lower maximum, than 1000.
On a system with max 256 open files, this would most likely succeed at 120.

<tag/<tt>maxchannel (0)</tt>/ 
if retrying an address would cause the number of simultaneously active
transport agents processing mail for the same channel to exceed
the specified value, the retry is postponed.
The check is repeated frequently so the address may be retried as soon
as possible after the scheduled retry interval. If the value is 0,
a value of 1000 is used instead.

<tag/<tt>maxring (0)</tt>/ Recipients are groupped into <tt>threads</tt>, 
and similar threads are groupped into <tt>thread-rings</tt>, where same 
transport agent can be switched over from one recipient to another. This 
defines how many transport agents can be running at any time at the ring.

<tag/<tt>skew (5)</tt>/ is the maximum number of retries before the retry 
time is aligned to a standard boundary (seconds since epoch, modulo primary 
interval). The lower this number (1 is lowest), the faster the alignment is 
done. The purpose of this alignment is to ensure that eventually a single 
transport agent invocation will be able to process destination addresses 
that arrived randomly to the <em>scheduler</em>.

<tag/<tt>user (root)</tt>/ is the user id of a transport agent processing 
the address. The value is either numeric (a uid) or an account name.

<tag/<tt>group (daemon)</tt>/ is the group id of a transport agent processing 
the address. The value is either numeric (a gid) or a group name.

<tag/<tt>command</tt>/ <tt>command (smtp -srl /var/log/smtp &dollar;host)</tt> 
is the command line used to start a transport agent to process the address.
The program pathname is specified relative to the <tt>&dollar;MAILBIN/ta/</tt>
directory. The string `<tt>&dollar;channel</tt>' is replaced by the current
matched channel, and `<tt>&dollar;host</tt>' replaced by the current matched 
host, from the destination address. It is strongly recommended that the 
`<tt>&dollar;host</tt>' is not to be used on a command definition, as it limits 
the usability of idled transporter.

<tag/<tt>bychannel</tt>/ is a keyword (with no associated value) that tells 
the <em>scheduler</em> that the transport agent specified in the command will 
only process destination addresses that match the first destination channel it 
encounters. This is automatically set when the string `<tt>&dollar;channel</tt>' 
occurs in the command, but may also be specified manually by this keyword. 
This is rarely used.

<tag/<tt>sm (8)</tt>/ to avoid the <em>scheduler</em> having to discover that 
the transport agent didn't consider a destination address the <em>scheduler</em>
thought it should have. The penalty for not using this keyword in such situations 
is that delivery of passed-over addresses will be staggered.

<tag/<tt>queueonly</tt>/ a clause with <tt>queueonly</tt> flag does not auto-start 
at the arrival of a message, instead it must be started by means of 
<em>smtpserver(8)</em> command <bf>ETRN</bf> through an SMTP connection.

</descrip>

For example, this is a complete configuration file:
<tscreen><verb>
# Default values
*/*	interval=1m expiry=3d retries="1 1 2 3 5 8 13 21 34"
	maxring=0 maxta=0 skew=5 user=root group=daemon
# Boilerplate parameters for local delivery and service channels
local/*	interval=10s expiry=3h maxchannel=2 command=mailbox
error	interval=5m maxchannel=10 command=errormail
hold/*	interval=5m maxchannel=1 command=hold
# Miscellaneous channels supported by router configuration
smtp/*.toronto.edu
smtp/*.utoronto.ca maxchannel=10 maxring=2
	command="smtp -srl /var/log/smtp"
smtp/*	maxchannel=10 maxring=5
	command="smtp -esrl /var/log/smtp"
uucp/*	maxchannel=5 command="sm -c $channel uucp"
</verb></tscreen>
The first clause (<tt>*/*</tt>) sets up default values for all
addresses. There is no command specification, so clause matching
will continue after address have picked up the parameters set here. 

The third clause (<tt>error</tt>) has an implicit host wildcard of `*', 
so it would match the same as specifying <tt>error/*</tt> would have.
 
The fifth clause (<tt>smtp/*.toronto.edu</tt>) has no further components 
so it selects the components of the following non-empty clause (the sixth).

Both the fifth and sixth clauses are specific to address destinations
within the <tt>TORONTO.EDU</tt> and <tt>UTORONTO.CA</tt> organization (the 
two are parallel domains). At most 10 deliveries to the <tt>smtp</tt> channel
may be concurrently active, and at most 2 for all possible hosts within
<tt>TORONTO.EDU</tt>. If `<tt>&dollar;host</tt>' is mentioned in the command 
specification, the transport agent will only be told about the message 
control files that indicate SMTP delivery to a particular host. The actual 
host is picked at random from the current choices, to avoid systematic
errors leading to a deadlock of any queue. 


<sect2>Resource Management
<p>

For resource management there are following configuration attributes: 

<descrip>
<tag/<tt>maxta=nnn</tt>/ Max number of transporter processes under 
the <em>scheduler</em>. 
<tag/<tt>maxchannel=nnn</tt>/ Max number of processes with this same 
`<tt>channel</tt>'. 
<tag/<tt>maxring=nnn</tt>/ Max number of processes with this set of 
threads. 
<tag/<tt>idlemax=time</tt>/ How long the non-active (idle) transporter 
processes are allowed to keep around. 
<tag/<tt>overfeed=nnn</tt>/ Max number of tasks to feed from the 
thread to the transporter agent when feeding jobs to it. The 
<em>scheduler</em> main-loop at the <tt>mux()</tt> is a bit sluggish, 
thus with this we can keep the transporters busy. 
<tag/<tt>ageorder</tt>/ Default is to randomize the order of tasks 
at the queue, when it is started, with this the order is that of 
the original spool-file MTIME. Oldest first. 
</descrip>


<sect2>mailq
<p>

Upon  accepting	a  TCP	connection on the MAILQ port (TCP
port 174), the scheduler dumps data to the TCP  stream  in
the  following  format  and immediately closes the connec-
tion:

The TCP stream syntax is:
<tscreen><verb>
version id\n
data in id-dependent format<close>
</verb></tscreen>

The first line (all bytes up to	an ASCII LF character,
octal 12) is used to identify the syntax of all bytes fol-
lowing the line terminator LF.  The first 8 characters  of
the first line are ``version'' as a check that this is
indeed a MAILQ port server that has been reached, the
remaining  bytes are the real data format identification.
The data is interpreted according to that format until the
terminating connection close.

Format identifiers should be registered with the author.
The only one currently defined is <tt>zmailer 1.0</tt>. For that
data format, the syntax of the data following the first LF
is:
<tscreen><verb>
Vertices:\n
(<key>:\t><msg-file>\t><n-addrs>; <off1>(,<offN>)*\t>[#<text>]\n)*
(Channels:\n
(<word>:\t>(><key>)+\n)+
Hosts:\n
(<word>:\t>(><key>)+\n)+)?
</verb></tscreen>
Where:
<descrip>
<tag/<verb>\n</verb>/ is an ASCII linefeed
<tag/<verb>\t</verb>/ is an ASCII tab
<tag/key/ is an unsigned decimal number
<tag/msg-file/ is a contiguous string (it is the message file name relative 
to a known directory)
<tag/n-addrs/ is an unsigned decimal number (number of addresses)
<tag/off1...offN/ are unsigned decimal numbers (address byte offsets)
<tag/text/ is a string not containing an ASCII linefeed (status message)
<tag/word/ is a contiguous string (a ``contiguous string'' is a sequence of 
printable non-space characters
</descrip>
For example, here is sample output from connecting to  the
MAILQ port:
<tscreen><verb>
version zmailer 1.0
Vertices:
311424:37141; 116
311680:64722; 151,331#128.100.8.4: Null read! (will retry)
312192:63471; 152#128.89.0.93: connect: Connection timed out (will retry)
Channels:
smtp:>311424>311680>312192
Hosts:
scg.toronto.edu:>311424
mv04.ecf.toronto.edu:>311680
relay1.cs.net:>312192
</verb></tscreen>

This is sufficient information to be able to reconstruct
the transport queues as seen by the scheduler process, and
to find more information than what is shown here by 
actually  looking  up  the  message	control	 and  data  files
referred to.

<sect2>Security Issues
<p>Text to be inserted here.














<!-- ref_agents.sgml -->
<!--<sect>Temporary section for testing!!!!!!!!!!!!!!!!!
<p>
Remove after testing!!
-->

<sect1>Delivery agents
<p>

The delivery agent programs normally form the final stage of message delivery.

These programs vary in function and facilities based on what they are
doing to the messages, and what kind of channels they handle.

<sect2>mailbox
<p>
The <em>mailbox</em> is a ZMailer transport agent which is usually
only run by the <em>scheduler(8)</em> program to deliver mail to
local user mailbox files. The <em>mailbox</em> program must be
run with root privileges and invoked with the same current 
directory as the <em>scheduler</em>, namely 
<tt>&dollar;POSTOFFICE/transport/</tt>.

Recipient addresses are processed  as follows: 

<itemize>
<item>Strip doublequotes around the address, if any. 
<item>Strip prefixing backslashes, if any.  
<item>If the address starts with a `<tt>|</tt>', the rest of the recipient address 
string is interpreted as  a shell command to be run. 
<item>If the address starts with a `<tt>/</tt>', the recipient address is a  filename
to append the message to. 
<item>Otherwise the recipient address must be a local user id. 
<item>If user is not  found,  and the first character of the address is a capital 
letter, the entire address is folded to lowercase and the user lookup is  retried.
</itemize>

If delivering to a user mailbox (<tt>&dollar;MAILBOX/userid/</tt>) which
does not exist, <em>mailbox</em> will try to create it. If the
<tt>&dollar;MAILBOX/</tt> directory is mounted from a remote system this
will succeed if the directory is group writable.

Some sanity checks are done on deliveries to files and mailboxes:

<itemize> 
<item>The file being delivered to must have one link only, and must be either 
<tt>/dev/null</tt> or a regular file.
<item>The file lock must be held. (See below for a chapter about locks.)  
</itemize>

There is a further sanity check on mailbox deliveries, namely if
the mailbox is not empty the <em>mailbox</em> program will
enforce 2 newlines as a separator before the message to be 
delivered. This guarantees that User Agents, like <em>Mail(1)</em>,
can find the about-to-be delivered message even  if the current
contents of the mailbox is corrupt.

When delivering to a process (by starting a Bourne shell to 
execute a specified command line), the environment is set up to 
contain <tt>&dollar;PATH</tt>, <tt>&dollar;SHELL</tt>, <tt>&dollar;HOME</tt>, 
<tt>&dollar;USER</tt>,
<tt>&dollar;SENDER</tt>,  <tt>&dollar;UID</tt> environment variables. The 
<tt>&dollar;HOME</tt> and <tt>&dollar;USER</tt> values are the recipient user's home
directory and login id respectively. The <tt>&dollar;SENDER</tt> value is
the sender address for the message (as it would appear in a From_
line), and the UID value is the owner id of the process. The
SIGINT and SIGHUP signals are ignored, but SIGTERM is treated
normally. If the process dumps core, it will be retried later.
Otherwise any non-zero exit status is taken as a permanent 
failure and will result in an error message back to the sender.
The actual data delivered to a file, mailbox,  or process, is
identical. It  consists of the concationation of a UUCP style
separator line, the message header specified in the message 
control file, and the message body from the original message file.
The separator line starts with ``From '' and is followed by the
sender address and a timestamp.

After all deliveries and just before exiting, the mailbox process
will poke comsat(8C) in case recipients have turned on biff(1).
The program may be compiled to look in the rwho files on the 
system for recipient names logged onto neighbouring hosts, in which
case the comsat on the remote host will be poked. Even if this
compile-time option is enabled, this will only be done for users
that have a <tt>.rbiff</tt> file in their home directory. (Unless an
`<tt>-DRBIFF_ALWAYS</tt>' compile option is used.)

<bf>Usage</bf>

<tscreen><verb>
mailbox [-8][-M][-c channel][-h localpart][-l logfile][-VabrH] 
</verb></tscreen>

<bf>Parameters</bf>

<descrip>
<tag/<tt>-c channel</tt>/ specifies which channel name should be keyed on. 
The default is local.
<tag/<tt>-h "localpart"</tt>/ specifies which of the possible multiple recipients is to 
be picked this time. Default is ``none'', which selects all local channel recipients, 
however when the routing is done with scripts storing some tokens (other than ``-'') 
into the ``host''-part, it is possible to process ``host-wise'', i.e. so that each 
user has his or her own lock-state, and not just everybody hang on the same lock(s)...
<tag/<tt>-l logfile</tt>/ specifies a logfile. Each entry is a line containing message 
id, pre-existing mailbox size in bytes, number of bytes appended, and the file name or 
command line delivered to.
<tag/<tt>-V</tt>/ prints a version message and exits.
<tag/<tt>-a</tt>/ the access time on mailbox files is, by default, preserved across
delivery, so that programs such as <tt>login(1)</tt> can determine if new
mail has arrived. This option disables the above action.
<tag/<tt>-b</tt>/ disables biff notification.
<tag/<tt>-r</tt>/ disables remote biff notification (if supported).
<tag/<tt>-8</tt>/ enables the MIME-QP-decoder to decode incoming  MIME-email with
Quoted-Printable encoded characters.
<tag/<tt>-M</tt>/ enables the creation of MMDF-style mail-folder in the  incoming
mail folder. The default is ``classic'' UNIX-style folder.
</descrip>

<bf>Interface</bf>

As with all transport agents, the program reads relative
pathnames of message control files from  standard input 
(terminated with two linefeeds), and produces diagnostic output on the
standard output. Normal diagnostic output is of the form:

<tscreen><verb>
id/offset<TAB>notify-data<TAB>status message
</verb></tscreen>

where id is the inode number of the message file, offset is a
byte offset within its control file where the address being
reported on is kept, status is one of ok, error, or deferred, and
the message is descriptive text associated with the report. The
text is terminated by a linefeed. Any other format (as might be
produced by subprocesses) is passed to standard output for 
logging in the scheduler log.
The exit status is a code from <tt>&lt;sysexits.h&gt;</tt>.

<bf>Locks</bf>

The locking scheme used on the system is configurable at the
runtime, and has separate parameters for mailboxes and files.
The data is configurable with zenv variable <tt>&dollar;MBOXLOCKS</tt> in which
the following characters have the meanings:

<descrip>
<tag/<tt>`:'</tt>/ Separates mailbox locks, and file-locks at the string. The left
side has mailbox locks, and the right side has locks for other
regular files. (Files with explicit paths defined.)
<tag/<tt>`.'</tt>/ For mailboxes only: Does ``dotlock'' (userid.lock), or (on Sun
Solaris) the <tt>maillock()</tt> mechanism.
<tag/<tt>`F'</tt>/ If the system has <tt>flock()</tt> system call, uses it to lock 
the entire file. (Ignored on systems without <tt>flock()</tt>)
<tag/<tt>`L'</tt>/ If the system has <tt>lockf()</tt> system call, uses it to lock 
the entire file. (Ignored on systems without <tt>lockf()</tt>) 
</descrip>

Locks are acquired in the same order as the key characters are listed.

The default for <tt>lockf()</tt> capable systems is: <tt>MBOXLOCKS=".L:L"</tt>
You can choose insane combinations of lock mechanisms, which on
some systems cause locks to fail always, like on <em>Linux-2.0</em> series
where programs must not use both <tt>lockf()</tt> and <tt>flock()</tt> locks.
It is extremely important that selected locking methods are consistent
throughout the system with all programs trying to acquire locks on
mail spools.

<bf>Environment</bf>

The default location for user mailbox files is 
currently <tt>/var/mail/</tt>. This may be modified by setting the variable
<tt>&dollar;MAILBOX</tt> in <tt>/etc/zmailer.conf</tt> to the directory containing 
user mailbox files, for example <tt>/usr/spool/mail/</tt>. This is best done 
in the ZMailer Config file. The variable <tt>&dollar;MBOXLOCKS</tt> is used to define locking schemes used for
mailbox spool files, and separately for other regular files.

<bf>Security</bf>
 
Like all parts of ZMailer, the mailbox chooses to
err on the overly cautious side.  In thecase of pipes being run under
the mailbox, the program in the pipe is started through <tt>/bin/sh</tt> with
severely sanitized environment variables, and with only the file
descriptors STDIN, STDOUT, and STDERR. Programs are refused from
running, if address analysis has found suspicuous data; external
messages cannot directly run programs, nor those addresses that
have had a security breach detected during (Same applies also
with writing into explicitely named files.)
The pipe subprogram is run with user-id it gets thru the address
privilege analysis during message routing, and it gets the groupid 
through lookup of <tt>getpwuid(uid)</tt>. That is, if you have multiple
usernames with same uid, there are no guarantees as to which of
them is used for the gid entry.

<bf>Subprogram Environment Variables</bf>

The mailbox sets the following eight environment variables for the subprograms it runs 
in the pipes:
<enum>
<item><tt>HOME</tt> The home directory path is taken from abovementioned getpwuid()
lookup.
<item><tt>USER</tt> Likewise the textual username.
<item><tt>SENDER</tt> is the incoming ``MAIL FROM:&lt;..&gt;'' address without brackets. For
an incoming error message, value ``&lt;&gt;'' is used.
<item><tt>ORCPT</tt> when present, is the XTEXT encoded ORCPT value received at the
message injection into this system. See RFC 1891 for details.
<item><tt>ENVID</tt> when present, is the XTEXT encoded ENVID value received at the
message injection into this system. See RFC 1891 for details.
<item><tt>ZCONFIG</tt> is the location of the ZMailer ZENV file.
<item><tt>MAILBIN</tt> is the value from ZENV.
<item><tt>MAILSHARE</tt> is the value from ZENV.
</enum>



<sect2>hold
<p>

hold - zmailer deferred processing transport agent

<bf>Description</bf>

hold is a ZMailer transport agent which is usually only
run by the <tt>scheduler(8)</tt> program to test conditions for
reprocessing of previously deferred message addresses.
The hold program must be run with the same current directory 
as the scheduler, namely <tt>&dollar;POSTOFFICE/transport/</tt>.

The program will interpret the host part of an address
destined for its channel as a condition that must be met
before the original address (in the user part) can be
reprocessed by the <em>router</em>. The condition specification
contains a general condition class name followed by colon
followed by a parameter string. The currently supported
condition classes are:

<descrip>
<tag/ns/ succeeds when the nameserver lookup indicated by
the parameter does not produce a temporary nameserver 
error. The parameter is a domain name followed by a slash 
followed by a standard Internet
nameserver Resource Record type name.

<tag/timeout/ succeeds when the time given by the parameter (in
normal seconds-since-epoch format) has passed.

<tag/io/ succeeds 10% of the time, to allow retry of temporary I/O failures.

<tag/script/ runs the named shell script with the optional given
argument. The parameter is a simple name, the
shell script name within the <tt>&dollar;MAILBIN/bin/</tt> directory,
optionally followed by a slash followed by an argument to be 
passed to the shell script.
</descrip>

For example:

<tscreen><verb>
NS:nic.ddn.mil/cname
TIMEOUT:649901432
IO:error
SCRIPT:homedir/joe
</verb></tscreen>

The condition class name is case-insensitive but is 
capitalised by convention. The parameter strings are 
case-preserved for condition class-specific interpretation.
Whitespace is not permitted.

The envelope of the resubmitted message is created from
the sender and (no longer deferred) recipient addresses,
and a ``via suspension'' header.

<bf>Usage</bf>

<tscreen><verb>
hold [ -c channel ] [ -V ]
</verb></tscreen>

<bf>Parameters</bf>

<tt>-c channel</tt> specifies which channel name should be keyed on. The default is hold.

<tt>-V</tt> prints a version message and exits.

<bf>Interface</bf>

As all transport agents, the program reads relative path-
names of message control files from standard input (terminated 
with two linefeeds), and produces diagnostic output
on the standard output. Normal diagnostic output is of
the form:

<tscreen><verb>
id/offset/status message
</verb></tscreen>

where id is the inode number of the message file, offset
is a byte offset within its control file where the address
being reported on is kept, status is one of ok, error, or
deferred, and the message is descriptive text associated
with the report. The text is terminated by a linefeed.
Any other format (as might be produced by subprocesses) is
passed to standard output for logging in the scheduler
log.

The exit status is a code from &lt;sysexits.h&gt;.



<sect2>smtp
<p>

<em>smtp</em> - zmailer SMTP client transport agent

<em>smtp</em> is a ZMailer transport agent which is usually only
run by the <tt>scheduler(8)</tt> to transfer messages to a remote
Internet host using the SMTP protocol. The <em>smtp</em> program
must be run with the same current directory as the scheduler, 
namely <tt>&dollar;POSTOFFICE/transport/</tt>.

The program scans the message control files named on stdin
for addresses destined for its channel and the host given
on the command line. If any are found, all matching
addresses and messages are transferred in a single SMTP
conversation. The destination host might in fact be
served by any available mail exchanger for that host.

<bf>Usage</bf>

<tscreen><verb>
smtp [ -78deEHrPsVxW ] [ -c channel ] [ -h heloname ] [ -l logfile ] 
[ -p remote-port ] [ -T timeout ] [ -F forcedest] [ -L localidentity ] host
</verb></tscreen>

<bf>Parameters</bf>

<descrip>
<tag/-7/ forces SMTP channel to be 7-bit, and thus forcing
all 8-bit texts to be MIME-QP-encoded for the transport.

<tag/-8/ forces SMTP channel to be 8-bit-clean, and as such,
to decode the message while transporting it (is it
is MIME QP encoded).

<tag/-c channel/ specifies which channel name should be keyed on.
The default is smtp.

<tag/-d/ turns on debugging output.

<tag/-e/ asks that for every destination address specification 
with a matching channel name, an MX lookup is
done on the hostname to see whether the currently
connected host can provide service for that destination. 
The default is to just do a textual name
comparison with the destination hostname as given
on the command line.

<tag/-E/ use the ``EHLO''-greeting only if the remote server
initial banner reports ``ESMTP'' on it.

<tag/-h host/ specifies the hostname for the SMTP HELO greeting.
The default is the hostname of the local system, as
returned by <tt>gethostname(2)</tt> or <tt>uname(2)</tt>.

<tag/-F forcedest/ overrides delivery destination by forcing all
email to be sent to given forcedest IP-number/hostname.

<tag/-H/ Disable the per default active forced 8-bit headers
conversion into MIME-2-format.

<tag/-L localident/ specifies (for multi-homed machines) that they
should use specified identity when connecting to
the destination. Think of server with multiple IP
numbers due to virtual hosting, for example. At
such systems there may be situation when virtual
identity needs to be used for reaching the destination system.

<tag/-l logfile/ specifies a log file where the complete SMTP command 
transaction will be copied. Each line in the
log will be prefixed with the process id of the
transport agent process, so the same log file can
be used by all SMTP clients.

<tag/-r/ asks to set up SMTP connections using a source TCP
port number under 1024. This is in the range of
port numbers only available to a privileged process
on some UNIX systems, which has led to some 
misguided attempts at mail security based on this
mechanism.

<tag/-s/ asks to report the progress of the SMTP conversation 
and data transfer on the command line in a way
that will be visible to <tt>ps(1)</tt>.

<tag/-x/ turns off MX lookups on delivery connections. This
may be used ignore public MX knowledge and do
exactly what the <em>router</em> says in cases where delivering 
to an explicit IP address is inappropriate.

<tag/-P/ disable SMTP-PIPELINING usage (ESMTP keyword: PIPELINING)

<tag/-T timeout/ specifies the timeout, in seconds, when waiting for
a response to an SMTP command. The timeout applies
to all SMTP command-response exchanges except for
the acknowledgement after terminating the DATA portion 
of a message transaction (after sending the
``.'' CRLF sequence). The default timeout is 10 
minutes, the minimum acceptable value is 5 seconds.
The timeout on the DATA acknowledgement is very
large, at least 24 hours.

<tag/-V/ prints a version message and exits.

<tag/-W/ turns on the DNS WKS checking, and if the remote
system does not have SMTP in its WKS-bits, email
delivery to such address is aborted with an error
message.
</descrip>

<bf>Interface</bf>

As all transport agents, the program reads relative path
names of message control files from standard input 
(terminated with two linefeeds), and produces diagnostic output
on the standard output. Normal diagnostic output is of
the form:

<tscreen><verb>
id/offset<TAB>notify-data<TAB>status message
</verb></tscreen>

where id is the inode number of the message file, offset
is a byte offset within its control file where the address
being reported on is kept, status is one of ok, error, or
deferred, and the message is descriptive text associated
with the report. The text is terminated by a linefeed.
Any other format (as might be produced by subprocesses) is
passed to standard output for logging in the scheduler
log.

The exit status is a code from <tt>&lt;sysexits.h&gt;</tt>.

<bf>Extended SMTP</bf>

When a user sends out 8-bit mail with the proper headers, this
module can send it out to conforming servers either in
8-bit transparent manner, or down-converting Content 
Transfer-Encoding: 8BIT to Content-Transfer-Encoding: 7BIT
or Content-Transfer-Encoding: QUOTED-PRINTABLE depending
on what is the mail contents.
This works only with Content-Type: text/plain thus no
fancy multipart/alternate et.al. schemes..
When Content-Transfer-Encoding: -header is not present in
the headers, and recipient has not declared 8-bit SMTP
capability, mail contents are treated with old 7-bit
stripping method.



<sect2><em>sm</em>
<p>

<em>sm</em> - zmailer Sendmail compatible transport agent

<em>sm</em> is a ZMailer transport agent which is usually only run
by the <tt>scheduler(8)</tt>, to deliver messages by invoking a
program with facilities and in a way compatible with a
<em>sendmail</em> mailer. The <em>sm</em> program must be run with the same
current directory as the scheduler, namely 
<tt>&dollar;POSTOFFICE/transport/</tt>.

The program scans the message control files named on stdin
for addresses destined for the channel and/or the host
given on the command line. If any are found, all matching
addresses and messages are processed according to the
specifications for the mailer in the configuration file.

The exit status of a mailer should be one of the standard
values specified in <tt>&lt;sysexits.h&gt;</tt>. Of these, EX_OK indicates 
successful delivery, and EX_DATAERR, EX_NOUSER,
EX_NOHOST, EX_UNAVAILABLE, and EX_NOPERM indicate permanent 
failure. All other exit codes will be treated as a
temporary failure and the delivery will be retried.

<bf>Usage</bf>

<tscreen><verb>
sm [ -8HQV ] [ -f configfile ] -c channel -h host mailer
</verb></tscreen>

<bf>Parameters</bf>

<descrip>
<tag/<tt>-8</tt>/ tells that the output is 8-bit clean, and for any
MIME message with QUOTED-PRINTABLE encoding the
coding can be decoded.

<tag/<tt>-Q</tt>/ tells that the transport channel will likely treat
poorly control characters like TAB, and possibly
SPACE too.. This encodes them all by using QUOTED-PRINTABLE encoding.

<tag/<tt>-f configfile</tt>/ specifies the name of a configuration file containing 
specifications of the various known <em>sendmail</em>
compatible mailer programs: how to invoke them and
how to process messages for them. The default is <tt>&dollar;MAILSHARE/sm.cf</tt>.

<tag/<tt>-c channel</tt>/ specifies which channel name should be keyed on.
There is no default. If this option is not specified, the <tt>-h</tt> option must be.

<tag/<tt>-h host</tt>/ specifies which host name should be keyed on.
There is no default. If this option is not specified, the <tt>-c</tt> option must be.

<tag/<tt>v-V</tt>/ prints a version message and exits.
</descrip>


<bf>Configuration</bf>

The configuration file associates the mailer keyword from
the command line with a specification of a delivery program. 
This is very similar to the way the definition of a
mailer in Sendmail requires flags, a program name, and a
command line specification. These are in fact the fields
of the entries of the configuration file. Lines starting
with whitespace or a '&num;' are ignored, and all others are
assumed to follow this format:

<tscreen><verb>
mailer flags program argument list
</verb></tscreen>

For example:

<tscreen><verb>
local mS sm/localm localm -r $g $u
prog - /bin/sh sh -c $u
tty rs /usr/local/to to $u
uucp U /usr/bin/uux uux - -r -a$g -gC $h!rmail ($u)
usenet m sm/usenet usenet $u
ean mn /local/lib/ean/gwsmean gwsmean -d $u
test n sm/test test $u
</verb></tscreen>

The mailer field extends from the beginning of the line to
the first whitespace. It is used simply as a key index to
the configuration file contents. Whitespace is used as
the field separator for all the fields.

The flags field contains a concatenation of one-letter
flags. If no flags are desired, a `-' character should be
used to indicate presence of the field. All normal <em>sendmail</em> flags 
are recognised, but the ones that do not make
sense in the context of ZMailer will produce an error.
The flags that change the behaviour of <em>sm</em> are:

<descrip>
<tag/b/ will activate BSMTP-type wrapping with ``hidden-dot''
algorithm; e.g. quite ordinary SMTP stream, but in
``batch mode''.

<tag/B/ The first `<tt>B</tt>' turns on similar BSMTP wrapping as
`<tt>b</tt>', but adds SIZE and, if the <em>sm</em> is started with
option `<tt>-8</tt>', also 8BITMIME options. The second `<tt>B</tt>'
adds there also DSN (Delivery Status Notification)
parameters.

<tag/E/ will prepend `&gt;' to any message body line starting
with `From '.

<tag/f/ adds ``<tt>-f sender</tt>'' arguments to the delivery program.

<tag/n/ will not prepend a From-space line (normal mailbox
separator line) to the message.

<tag/r/ adds ``<tt>-r sender</tt>'' arguments to the delivery program.

<tag/S/ will run the delivery program with the same real
and effective uid as the <em>sm</em> process. If this flag
is not set, the delivery program will be run with
the real uid of the <em>sm</em> process. This may be useful
if <em>sm</em> is setuid.

<tag/m/ informs <em>sm</em> that each instance of the delivery program 
can deliver to many destinations. This
affects <bf><tt>&dollar;u</tt></bf> expansion in the argument list, see
below.

<tag/P/ prepends a <tt>Return-Path:</tt> header to the message.

<tag/U/ will prepend a From-space line, with a ``remote from
myuucpname'' at the end, to the message. This is
what is expected by remote rmail(1) programs for
incoming UUCP mail.

<tag/R/ use CRLF sequence as end-of-line sequence. Without it, will use 
LF-only end-of-line sequence.

<tag/X/ does SMTP-like `hidden-dot' algorithm of doubling all dots that are 
at the start of the line.

<tag/7/ will strip (set to 0) the 8th bit of every character in the message.
</descrip>

The path field specifies the location of the delivery program. 
Relative pathnames are allowed and are relative to
the <tt>&dollar;MAILBIN/</tt> directory.

The arguments field extends to the end of the line. It
contains whitespace-separated argv parameters which may
contain one of the following sequences:

<tt>&dollar;g</tt> which is replaced by the sender address.

<tt>&dollar;h</tt> which is replaced by the destination host.

<tt>&dollar;u</tt> which is replaced by the recipient address. If the

<tt>-m</tt> mailer flag is set and there are several recipients for this message, the argument containing the <tt>&dollar;u</tt> will be replicated as necessary for each recipient.

<bf>Iterface</bf>

As all transport agents, the program reads relative pathnames 
of message control files from standard input (terminated 
with two linefeeds), and produces diagnostic output
on the standard output. Normal diagnostic output is of
the form:

<tscreen><verb>
id/offset<TAB>notify-data<TAB>status message
</verb></tscreen>

where id is the inode number of the message file, offset
is a byte offset within its control file where the address
being reported on is kept, status is one of ok, error, or
deferred, and the message is descriptive text associated
with the report. The text is terminated by a linefeed.
Any other format (as might be produced by subprocesses) is
passed to standard output for logging in the scheduler
log.

The exit status is a code from <tt>&lt;sysexits.h&gt;</tt>.


<sect2>libta - Transport Agent Support Library
<p>

This is the library that all transport agents use, and several of its
functions are intended to aid message processing.

<sect3>Function groupings
<p>
Transport agent support library function groups are:

<itemize>
<item>Message file manipulation routines.
<item>Diagnostics routines.
</itemize>

<sect3>Function listings 

<sect3>Function usage examples

<sect2>Security Issues
<p>Text to be inserted here.
 
<!-- ref_utils.sgml -->
<sect1>Utilities
<p>

There is considerable collection of various utilities in the
ZMailer package. Not all of them even become installed into
your system in all situations.

<sect2>vacation
<p>

<em>vacation</em> automatically replies to incoming mail. The canned 
reply is contained in the file <tt>.vacation.msg</tt>, that you should 
create in your home directory (or the file <tt>Msgfile</tt> specified by 
the <tt>-m</tt> option).

This file should include a header with at least a <tt>Subject:</tt> line 
(it should not include a <tt>To:</tt> line -- if you want, you may include 
a <tt>From:</tt> line, especially if you use the <tt>-m</tt> option). 
For example:

<bf>Usage</bf>

To start <em>vacation</em>, run the command <tt>vacation start</tt>. 
It will create a <tt>.vacation.msg</tt> file (if you don't already 
have one) in your home directory containing the message you want to send 
people who send you mail, and a <tt>.forward</tt> file in your home 
directory containing a line of the form:

<tscreen><verb>
"\name", "|/opt/mail/bin/vacation name"
</verb></tscreen>

where name is your login name. Make sure these files and your home 
directory are readable by everyone. Also  make sure  that  no  one  
else  can  write  to  them,  and  that  no  one  can  write  to  your  
home  directory. (<tt>chmod og-w &dollar;HOME &dollar;HOME/.forward</tt>)

To stop vacation, run the command <tt>vacation stop</tt> It will move the 
<tt>.forward</tt> file to <tt>.vacforward</tt>, and the automatic 
replies will stop.

<tt>vacation start vacation stop vacation -I vacation &lsqb; -tN &rsqb; 
&lsqb; -mMsgfile &rsqb; &lsqb; -d &rsqb; &lsqb;user&rsqb;</tt>

<bf>Parameters</bf>

<descrip>
<tag/<tt>-I</tt>, <tt>-i</tt>/ initialize the <tt>.vacation.pag</tt> 
and <tt>.vacation.dir</tt> files and start vacation.

If the <tt>-I</tt> (or <tt>-i</tt>) flag is not specified, vacation 
tries to reply to the sender.

<tag/<tt>-tN</tt>/ Change the interval between repeat replies to the same 
sender. The default is one week. A trailing <tt>s</tt>, <tt>m</tt>, 
<tt>h</tt>, <tt>d</tt>, or <tt>w</tt> scales N to seconds, minutes, 
hours, days, or weeks respectively.

<tag/<tt>-mMsgfile</tt>/ specifies the file in which the message to be 
sent is kept. 
The default is <tt>&dollar;HOME/.vacation.msg</tt>.

<tag/<tt>-r</tt>/ interval defines interval in days when not to answer 
again to the same sender. (Default is 1 day.)

<tag/<tt>-d</tt>/ disables the list of senders kept in the 
<tt>.vacation.pag</tt> and <tt>.vacation.dir</tt> files.
</descrip>

<bf>Example</bf>

<tscreen><verb>
Subject: I am on vacation

I am on vacation until July 22. If you have something urgent, please 
contact Joe Jones (joe@blah.utoronto.ca). --john
</verb></tscreen>

No message is sent if the ``user'' specified in the vacation  
command (if nothing is specified, it uses your username) does 
not appear explicitly in the <tt>To:</tt> or <tt>Cc:</tt> lines of the 
message, which prevents messages from being sent back to mailing lists 
and causing loops.

A list of senders is kept in the files <tt>.vacation.pag</tt> and 
<tt>.vacation.dir</tt> in your home directory. These are dbm database 
files. (Note: not all database systems have two files, either may be 
missing.) The vacation message is in <tt>.vacation.msg</tt> and 
the automatic reply is activated by the <tt>.forward</tt> (and 
saved in <tt>.vacforward</tt>) The default vacation message is 
stored in <tt>/opt/mail/vacation.msg</tt>

On machines running ZMailer, the <tt>name</tt> argument 
to <em>vacation</em> is optional, and the <tt>&dollar;USER</tt> 
environment variable is used to determine where to look for the 
message and the list of previous recipients.

The <tt>&dollar;SENDER</tt> variable is checked first to determine 
the reply destination. It is normally set to the <bf>SMTP</bf> 
<bf>MAIL FROM</bf> address or equivalent. This is an additional 
safeguard against sending replies to mailing lists, the PostMaster 
or the mailer daemon, since standards and common sense dictate that 
it never points back to an address that could cause a loop. The 
<tt>From_</tt> line is used only as a last resort.

<sect2>makedb
<p>

The way the ZMailer uses DBM entries is by using strings with 
their terminating <tt>NULL</tt> as keys, and as data.. Thus 
the length is <tt>strlen(string)+1</tt>, not <tt>strlen(string)</tt> !

WARNING: Policy data parsing does use unchecked buffers!

<tscreen><verb>
Usage: makedb [-a|-p] dbtype database.name [infilename|-]
</verb></tscreen>

Dbtypes are: <tt>ndbm gdbm btree bhash</tt>

If no <tt>infilename</tt> is defined, <tt>database.name</tt> is assumed.

<descrip>
<tag/<tt>NDBM</tt>/ appends <tt>.pag</tt>, and <tt>.dir</tt>
into the actual db file names.
<tag/<tt>GDBM</tt>/ <bf>does not</bf> append <tt>.gdbm</tt>
into the actual db file name.
<tag/<tt>BTREE</tt>/ <bf>does not</bf> append <tt>.db</tt>
into the actual db file name.
<tag/<tt>BHASH</tt>/ appends <tt>.pag</tt>, and <tt>.dir</tt>
into the actual db file names.
</descrip>

The <tt>-a</tt> option is for parsing input that comes in 
<tt>aliases</tt> format: <tt>key: data,in,single,long,line</tt>

<sect2>dblook
<p>

The way the ZMailer uses DBM entries is by using strings with 
their terminating <tt>NULL</tt> as keys, and as data.. Thus the 
length is <tt>strlen(string)+1</tt>, not <tt>strlen(string)</tt> !

<tscreen><verb>
Usage: dblook [-dump] dbtype database.name [key]
</verb></tscreen>

Dbtypes are: <tt>ndbm gdbm btree bhash</tt>

<descrip>
<tag/<tt>NDBM</tt>/ appends <tt>.pag</tt>, and <tt>.dir</tt> 
into the actual db file names.
<tag/<tt>GDBM</tt>/ <bf>does not</bf> append <tt>.gdbm</tt> 
into the actual db file name.
<tag/<tt>BTREE</tt>/ <bf>does not</bf> append <tt>.db</tt> 
into the actual db file name.
<tag/<tt>BHASH</tt>/ appends <tt>.pag</tt>, and <tt>.dir</tt> 
into the actual db file names.
</descrip>

<sect2>policy-builder.sh
<p>

<tscreen><verb>
#! /bin/sh
#
# Sample smtp-policy-db builder script.
#
# This merges following files from $MAILVAR/db/ directory:
#	smtp-policy.src
#	localnames	  ('= _full_rights')
#	smtp-policy.relay ('= _full_rights')
#	smtp-policy.mx	  ('relaytargets +')
#	smtp-policy.spam  ('= _bulk_mail')
#
# These all together are used to produce files:  smtp-policy.$DBEXT
# The produced database retains the first instance of any given key.

ZCONFIG=@ZMAILERCFGFILE@
. $ZCONFIG

umask 022

cd $MAILVAR/db

if [ ! -f smtp-policy.src ] ; then
	echo "No $MAILVAR/db/smtp-policy.src input file"
	exit 64 # EX_USAGE
fi

lynx -source http://www.webeasy.com:8080/spam/spam_download_table \
   > smtp-policy.spam.new &ero;&ero; mv smtp-policy.spam.new smtp-policy.spam

# Fork off a subshell to do it all...
(
  # The basic boilerplate
  cat smtp-policy.src

  # Localnames
  cat localnames | \
  awk '/^#/{next;} NF >= 1 {printf "%s = _full_rights\n",$1;}'

  # smtp-policy.relay
  # (Lists domains and networks that are allowed to use us as relay)
  if [ -f smtp-policy.relay ] ; then
    cat smtp-policy.relay | \
    awk '/^#/{next;} NF >= 1 {printf "%s = _full_rights\n",$1;}'
  fi

  # smtp-policy.mx
  # (Lists domains that are allowed to use us as inbound MX relay for them)
  if [ -f smtp-policy.mx ] ; then
    cat smtp-policy.mx | \
    awk '/^#/{next;} NF >= 1 {printf "%s relaytarget +\n",$1;}'
  fi

  # smtp-policy.spam
  # (Lists users, and domains that are known spam sources)
  # (We use file from "http://www.webeasy.com:8080/spam/spam_download_table"
  #  which is intended for QMAIL, and thus needs to be edited..)
  if [ -f smtp-policy.spam ] ; then
    cat smtp-policy.spam | tr "[A-Z]" "[a-z]" | sort | uniq | \
    awk '/^@/{ # Domain, but ZMailer processes them without '@'
	  printf "%s = _bulk_mail\n", substr($1,2);
	  next;
	}
	{ # All other cases are usernames with their domains
	  printf "%s = _bulk_mail\n", $1;
	}'
  fi

# --------- end of subshell
) | tee smtp-policy.dat | \
$MAILBIN/makendbm -p $DBTYPE smtp-policy-new -

case $DBTYPE in
dbm)
	mv smtp-policy-new.dir  smtp-policy.dir
	mv smtp-policy-new.pag  smtp-policy.pag
	;;
ndbm)
	mv smtp-policy-new.dir  smtp-policy.dir
	mv smtp-policy-new.pag  smtp-policy.pag
	;;
gdbm)
	mv smtp-policy-new.gdbm smtp-policy.gdbm
	;;
btree)
	mv smtp-policy-new.db   smtp-policy.db
	;;
esac

exit 0
</verb></tscreen>

<sect2>autoanswer
<p>

The <em>autoanswer</em> program is intended to be placed into
system global aliases database as following entry:

<tscreen><verb>
autoanswer:  "| /path/to/MAILBIN/autoanswer"
</verb></tscreen>

It yields a reply message for all, except the error messages, nor
to those with <tt>X-autoanswer-loop:</tt> header in them.

The reply sends back the original incoming message headers in the
message body along with some commentary texts.

The program is, in reality, a perl script which can easily be tuned
to local needs.

<tscreen><verb>
#!@PERL@

##########################################################################
#
# Autoanswer.pl 1.0 for ZMailer 2.99.48+
# (C) 1997 Telecom Finland
#          Valtteri Karu <valtteri.karu@tele.fi>
# 
# This program sends autoreply and the original headers to the originator 
# of the message. Version 2.99.48+ of the Zmailer is required for detecting
# possible false addresses.
#
# USAGE:
#
# Create an alias for the address to use:
# autoreply: "|/path/to/autoanswer.pl"
#
##########################################################################

$nosend = 0;
$double = 0;
$address = $ENV{'SENDER'};

if( ! -r "$ENV{'ZCONFIG'}") {
    LOG("zmailer.conf missing");
    exit 2;
}

open(ZMAILER,"< $ENV{'ZCONFIG'}" );
while(<ZMAILER>) {
    chomp;
    split(/=/);
    $ZMAILER{$_[0]}=$_[1];
}

close ZMAILER;

$logfile = $ZMAILER{'LOGDIR'} . "/autoanswer";

while (<STDIN>) {

    $text = $_;

    if (($text eq "\n") &ero;&ero; ( $double = 1)) {
	last;
    }

    if (($text eq "\n") &ero;&ero; ( $double = 0)) {
	$double = 1;
	next;
    }
    
    if ($text =~ "X-autoanswer-loop: ") {
	$nosend = 1;
	LOG("Looping message, sender=$address");
    }

    $double = 0;

    push(@header,$text);
}

if (($address eq '<>') || ($nosend = 0)) {
    LOG("SENDER invalid");
    exit 1;
}

$outfile = $ZMAILER{'POSTOFFICE'} . "/public/autoanswer.$$";
#$outfile = "/tmp/aa.$$";
$now = time;
$txttime = localtime(time);

open(OUT,">$outfile");
select(OUT);
print "channel error\n";
print "to $address\n";
print "env-end\n"; 
print "From: Autoreply service <postmaster>\n";
print "To: $address\n";
print "Subject: Autoreply\n";
print "X-autoanswer-loop: Megaloop \n\n";
print "      This is autoreply answer message by your request.\n\n";
print "      Original message was received at UNIX time $now;\n";
print "      which means '$txttime' in cleartext.\n\n";
print "      Headers were:\n\n";
print "------------------------------------------------------------------------------\n";
print @header;
print "------------------------------------------------------------------------------\n";
print "\n      Have a nice day.\n";
select(STDOUT);
close OUT;
$inode=(stat($outfile))[1];
$newfile=$ZMAILER{'POSTOFFICE'} . "/router/$inode";
rename($outfile, $newfile);
LOG("Sent to $address");
exit 0;

sub LOG {

	open(LOGf, ">>$logfile");
	$ttime = localtime(time);
	printf (LOGf "$ttime autoanswer: @_\n");
	close LOGf;
}
</verb></tscreen>

<sect2>newdb
<p>

This is elementary wrapper script building binary databases
with <tt>makedb</tt> utility into a temporary file, and replacing
the old files with the new ones in proper order for the 
<bf>router</bf>'s automatic source change detecting relation 
parameter <tt>-m</tt> to work correctly.

<bf>Usage</bf>

<tscreen><verb>
newdb /db/path/name [input-file-name]
</verb></tscreen>

This script uses system <tt>ZCONFIG</tt> file to find out the desired
database type, and derives the actual database file names from the 
variable.

Suffix selection rules are:

<tscreen><verb>
dbm     .pag and .dir
ndbm    .pag and .dir
gdbm    .gdbm
btree   .db   
</verb></tscreen>



<!-- app_scripts.sgml -->
<appendix>
<sect>Sample Router Configuration Scripts
<p>Text to be inserted here.

The following are examples of the router configuration scripts SMTP+UUCP.cf, crossbar.cf, process.cf, and rrouter.cf.

<sect1>SMTP+UUCP.cf
<p>
ZMailer 2 configuration file for a generic SMTP host (with UUCP links)

<tscreen><verb>
ZCONFIG=@ZMAILERCFGFILE@

. $ZCONFIG

PATH=.:$MAILSHARE/cf:$MAILBIN/bin ; export PATH
PS1=z$PS1
</verb></tscreen>

Configure error logging (squirrel)

<tscreen><verb>
squirrel -breakin
squirrel badheader
</verb></tscreen>

Domains with these toplevels will not be canonicalized via DNS lookup.
This list is from ISOC table of 16-April-95.

The quoted string <tt>"ad...zw"</tt> should be on one line in the actual SMTP+UUCP.cf file.

<tscreen><verb>
toplevels="ad ae af ag ai al am an ao aq ar as at au aw az ba bb bd be bf bg bh bi bj bm bn 
bo br bs bt bv bw by bz ca cc cf cg ch ci ck cl cm cn co com cr cu cv cx cy cz de dj dk dm 
do dz ec edu ee eg eh es et fi fj fk fm fo fr ga gb gd ge gf gh gi gl gm gn gov gp gq gr gt 
gu gw gy hk hm hn hr ht hu id ie il in int io iq ir is it jm jo jp ke kg kh ki km kn kp kr 
kw ky kz la lb lc li lk lr ls lt lu lv ly ma mc md mg mh mil ml mm mn mo mp mq mr ms mt mu 
mv mw mx my mz na nc ne net nf ng ni nl no np nr nt nu nz om org pa pe pf pg ph pk pl pm pn 
pr pt pw py qa re ro ru rw sa sb sc sd se sg sh si sj sk sl sm sn so sr st sv sy sz tc td tf 
tg th tj tk tm tn to tp tr tt tv tw tz ua ug uk um us uy uz va vc ve vg vi vn vu wf ws ye yu 
za zm zr zw"
</verb></tscreen>

The transport preference order

<tscreen><verb>
protocols='routes smtp uucp'
</verb></tscreen>

Will the  MAILVAR/lists/listname  show out sender identity as
either:  owner-listname, or:  listname-owner?

<tscreen><verb>
if true ; then # Change to "false" to get "pre-owner" mode
	preowner=""
	postowner="-owner"
else
	preowner="owner-"
	postowner=""
fi
</verb></tscreen>

Does our ``local'' channel accept domain (@) at the user part?
ZMailer's mailbox does accept.  If you use something else, and
it doesn't accept, comment this away.

<tscreen><verb>
localdoesdomain=1
</verb></tscreen>

We may want .forward and mailing list files to be private, i.e., we ignore
the current privileges when checking the privileges of such files.
Don't add `include' to this list, since anyone can :include: any file.

<tscreen><verb>
private='.forward maillist'
</verb></tscreen>

Set up dependency checking.

<tscreen><verb>
. consist.cf
require siteinfo router crossbar process server
</verb></tscreen>

The following are standard setup files and must be loaded in this order

<tscreen><verb>
. standard.cf
. trusted.cf
</verb></tscreen>

Load the databases so they and the variables defined (e.g. network-specific
node names for this host) can be used in the site specific configuration.

<tscreen><verb>
for method in $protocols
do
	test -f $MAILSHARE/cf/i-${method}.cf && . i-${method}.cf
done

mailconf () {
	local hname

	# My official hostname
	if [ -f /bin/hostname ]; then
		rawhostname=$(/bin/hostname)
	elif [ -f /etc/sys_id ]; then
		read rawhostname < /etc/sys_id
	else
		rawhostname=$(/bin/uname -n)
	fi

	hname=$(canon $rawhostname)
</verb></tscreen>

Try to discover the organizational domain name.

<tscreen><verb>
	orgdomain=$hname
	sift $hname in
	$rawhostname\.(.+)
		orgdomain=\1
		;;
	tfis
	hostname=$hname

	# This is what it will say on out mail
	mydomain=$hostname
}

orgdomains=x
: ${MAILCONF:=/etc/mail.conf}
if [ ! -r $MAILCONF ]; then
	echo "$0: missing $MAILCONF: using the following values:"
	mailconf
	echo orgdomain=$orgdomain
	echo hostname=$hostname
	echo mydomain=$mydomain
	provide siteinfo
else
	. $MAILCONF && provide siteinfo
fi
[ "$orgdomains" = x ] && orgdomains=$orgdomain
</verb></tscreen>

Set hostname to enable message-id generation and checking.

<tscreen><verb>
hostname $hostname

. aliases.cf
. canon.cf
. rrouter.cf
. crossbar.cf

for method in $protocols
do
	. p-${method}.cf
done

. process.cf
. server.cf

consist || exit 1
</verb></tscreen>

<sect1>Crossbar.cf
<p>

<tscreen><verb>
provide crossbar
</verb></tscreen>

The crossbar function makes the policy decisions of how the instance of
a message between a particular sender and recipient should be treated.
The 'from' and 'to' parameters are quads, i.e., in the form

	(channel host user attributes)

The function may modify any of these elements of both the from and to
addresses, and must select a message header address rewriting function
to be applied to this message instance.  If the return value is nil or
empty, the instance is completely ignored, to the point that if there are
no other recipients specified a complaint will be generated saying there
are <bf>no</bf> recipients specified.

<tscreen><verb>
crossbar (from, to) {
	local rewrite destination tmp
</verb></tscreen>

Count them...  (in <tt>process.cf</tt>)
(we could use this as an ultimate duplicate remover too...)

<tscreen><verb>
	db add recipients "$(user $to)" "$(user $from)"

Intercept (drop, redirect, bounce, save) the message

	tmp=$(intercept "$(user $from)") &&
		case "$(car $tmp)" in
</verb></tscreen>
Dropping error types for from addresses is necessary to avoid mail loops.
<tscreen><verb>
		drop|error)
			return ;;
		file)	LOGMSG="$LOGMSG $(car $(cdr $tmp))" ;;
		esac

</verb></tscreen>

Only intercept mail that is not from the local postmaster,
so that error messages can find their way back.

<tscreen><verb>
	[ "$(channel $from)" = local -a "$(user $from)" = postmaster ] ||
	tmp=$(intercept "$(user $to)") &&
		case "$(car $tmp)" in
		drop)	return ;;
		error)	setf $(channel $to) error
			setf $(host $to) $(car $(cdr $tmp))
			;;
		file)	LOGMSG="$LOGMSG $(car $(cdr $tmp))" ;;
		esac
</verb></tscreen>
If we do any alias expansion from the crossbar, we should do this:
<tscreen><verb>
db flush expansions
</verb></tscreen>
Determine which rewrite function (for message header addresses) to use.
<tscreen><verb>
	case $(channel $to) in
	smtp|smtpx)
		#case "$(channel $from)" in
		#smtp|smtpx)	# Address should be forwarded the way the arrive
		#	rewrite=null ;;
		#*)	rewrite=internet ;;
		#esac
		rewrite=internet
		;;
	error)	rewrite=null ;;
	local)	case "$(channel $from)" in
		local)	#rewrite=intramachine
			rewrite=internet ;;
		*)	# addresses should be saved the way they arrive
			rewrite=null ;;
		esac
		;;
	usenet)	rewrite=internet ;;
	ean)	rewrite=ean_useratdomain ;;
	*)	# This is usually UUCP or BITNET
		# We want to determine the final destination host/domain
		destination="$(uucproute "$(user $to)")"
		if [ "$(host $to)" ]; then
			destination="$(host $to)"!"$destination"
		fi
		sift "$destination" in
		.*!([^!]+)![^!]+
			destination="\1" ;;	# destination domain
		.*\.(bitnet|netnorth|earn|cdn)
			rewrite=smtp_useratdomain
			break ;;			# reply to user@domain
		.*	rewrite=internet ; break ;;	# default sensible thing
		tfis
		;;
	esac
</verb></tscreen>
The alias expansion might want to modify the envelope sender
of the message instance.  Here we cooperate in the scheme which
is to set the 'sender' attribute of the destination address.
<tscreen><verb>
	tmp="$(get $(attributes $to) sender)" && [ x"$tmp" != x ] &&
		from=(local "$tmp" "$tmp" $(attributes $from))


	case "$(channel $from)" in
	defrt1*)
		setf "$(user $from)" "$(bitnetroute "$(user $from)")"
		if [ $rewrite = internet ]; then
			rewrite=bitnet2internet
		fi
		;;
	esac
</verb></tscreen>
Rewrite the envelope addresses appropriately.
<tscreen><verb>
	case "$(channel $to)" in
#	uucp|local)
	uucp)
</verb></tscreen>
Local destination on a system that delivers in UCB Mail
compatible mail spool files means that the From_ line
must be in all-! form, which is the same as the UUCP
transport requirement.
<tscreen><verb>
		setf "$(user $from)" "$(uucproute "$(user $from)")"
		setf "$(user $to)" "$(uucproute "$(user $to)")"
		sift "$(user $to)" in
		(.)!(.*)	if [ \1 = $(host $to) ]; then
					setf "$(user $to)" \2
				fi
				;;
		tfis
		sift "$(user $to)" in
		(.)\.uucp!(.*)	setf "$(user $to)" \1!\2 ;;
		tfis
		;;
#	smtp)
	smtp|smtpx|local|bsmtp3*)
		tmp="$(smtproute "$(user $from)")"
		sift "$tmp" in
		(@$hostname[:,].*)|([^@:,]+@$hostname)
			break ;;
		.*
			# tmp="@$hostname:$tmp"  # <-- that creates RFC-822
						 #     source-routing, AVOID!
			tmp="$tmp"
			;;
		@(.+):(.+:.+)
			tmp="@\1,\2" ; continue ;;
		tfis
		setf "$(user $from)" "$tmp"
		sift "$(user $to)" in
		(^/).*	setf "$(user $to)" "$(smtproute "$(user $to)")" ;;
		tfis

		;;
	ean)	
		setf $(user $from) "$(ean_useratdomain "$(user $from)")"
		setf "$(user $to)" "$(ean_useratdomain "$(user $to)")"
		;;
	usenet)
		setf $(user $from) "$(uucproute "$(user $from)")"
		sift $(user $from) in
		$hostname!.*	;;
		.*	setf $(user $from) $hostname!$(user $from) ;;
		tfis
		# newsgroup name only
		setf "$(user $to)" $(localpart "$(user $to)")
		;;
#	bsmtp3|bsmtp3nd)
#		setf $(user $from) "$(bitnetroute "$(user $from)")"
#		tmp="$(bitnetroute "$(user $to)")"
#		sift "$tmp" in
#		.*@([^.]).uucp
#			tmp="$(bitnetShortroute "$(user $to)")" ;;
#		tfis
#		setf "$(user $to)" "$tmp"
#		rewrite=bitnetShortroute
#		;;

	defrt1)
		setf $(user $from) "$(bitnetroute "$(user $from)")"
		setf $(user $to) "$(bitnetroute "$(user $to)")"
		rewrite=bitnetroute
		sift "$(user $to)" in
		(.*)[!%](.+)@(.*)
			to=(error bitnetgw "\3" $(attributes $to))
			rewrite=null
			;;
		tfis
		;;
	esac

	#log recipient: "$(channel $to)" "$(host $to)" "$(user $to)"
	return ($rewrite $from $to)
}	# end of crossbar
</verb></tscreen>

If you want to intercept specific mail messages, this function and the
associated code in the crossbar and process functions will let you do it.  
There are three possible actions:

<itemize>
<item>drop	- completely ignore this address
<item>error	- return the specified error message
<item>file	- append the message file to the specified file
</itemize>

Both the file and error actions require an argument, which necessitates
the use of multiple-value return (i.e., return a list) in all cases.

If you don't want to intercept anything, this function should return failure.
The stub defined here is the usual case, you can override it in the host-
specific cf file.

<tscreen><verb>
intercept (address) {
#	case "$(smtp_useratdomain "$address")" in
#	*@pdq*)		return (file /var/scr/pdq) ;;
#	rayan@csri.*)	return (drop) ;;
#	bitftp*@*)	return (error bounce) ;;
#	esac

	return 1
}
</verb></tscreen>

On mail from one local user to another, we don't want to see all the
long domain name extensions.  This can cause problems with silly UAs,
if it does you can just redefine <tt>intramachine</tt> to call 
<tt>null</tt> in your
site or host-specific configuration files.

<tscreen><verb>
intramachine (address) {		# strip hostname if it came from here
	sift "$address" in
	(.*)@($hostname|$mydomain)
		address="$(condquote "\1")" ;;
	tfis
	return "$address"
}	# end of intramachine


null (address) {
	return "$address"		# surprise!
}
</verb></tscreen>

This is usually the default message-header address rewriting function.
It is responsible for hostname hiding and qualification.

<tscreen><verb>
internet (address) {
	address="$(canonicalize "$address")"	# Canonicalize does local
						# hostname hiding...
	sift "$address" in
	(.*)<@(.+)>(.*)
			#if [ $(deliver \2) ]; then	# hostname hiding
			#	address="\1@${mydomain}\3"
			#	break
			#fi
			address="\1@\2\3" # No hostname hiding...
			;;
	(.*)<(.+)>(.*)	address="\1\2\3" ;;		# defocus
	[^@]+		
		# This is a local part address w/o any domains!
		address="$(condquote "$address")"
		address="$address@$mydomain"	# add our hostname
		;;
	tfis
	return "$address"
}	# end of internet
</verb></tscreen>

<sect1>Process.cf
<p>
This is the protocol switch function.  It keys off the form of the filename
to determine how to process a particular class of messages.  It is expected
that an internal function will be called to orchestrate the processing of
the message and enforce proper semantics.

The file argument is the name of a file in the <tt>&dollar;POSTOFFICE/router</tt>
directory.
<tscreen><verb>
process (file) {

	db flush pwuid
	db flush pwnam
	db flush fullname
	db flush hostexpansions
	db flush recipients
</verb></tscreen>
Since we cannot detect that the password database has been updated under
our feet, we flush the cached information every once in a while (in this
case, before every message).
<tscreen><verb>
	LOGMSG=''
</verb></tscreen>
The LOGMSG variable is used by the intercept facility (in <tt>crossbar.cf</tt>)
to make sure only a single copy of a message is saved when required.
Each sender - recipient address pair can cause an intercept which can
specify a file to save the message to.  This variable is appended to
elsewhere, and processed at the end of this function.
<tscreen><verb>
	case "$file" in
#	[0-9]*.x400)	x400 "$file" ;;
#	[0-9]*.uucp)	uucpfilter "$file" > /tmp/X.$$
#			cat /tmp/X.$$ > "$file"
#			rfc822 "$file" ;;
	[0-9]*)		rfc822 "$file" ;;
	core*)		/bin/mv "$file" ../$file.router.$$
			return
			;;
	*)		/bin/mv "$file" ../postman/rtr."$file".$$
			return
			;;
	esac

	[ $? ] && return 0	# Leave when they returned failure..
</verb></tscreen>
The file names in the <tt>&dollar;POSTOFFICE/router</tt> directory are determined by
the parameter to the mail_open() C library routine.  This case
statement knows about the various message file types needed on your
system, and arranges appropriate processing of each.  The internal
function <tt>rfc822</tt> expects a file name as argument, and determines the
semantics of the message and of the configuration code.  For example,
the <tt>router</tt>, <tt>crossbar</tt>, and <tt>header_defer</tt> functions have semantics only
because the <tt>rfc822</tt> function knows about them.  There are no other
message formats supported in this distribution.
<tscreen><verb>
	log info: recipients $(db count recipients) $(elements $(cdr $(cdr $(cdr $(cdr $envelopeinfo))))) '
'
</verb></tscreen>
For statistics gathering we print out the envelope information property
list in its entirety, except for the file name, and the message id, both
of which were logged earlier (in C code).
<tscreen><verb>
	for f in $LOGMSG
	do
		{ echo "==${file}==$(rfc822date)==" ;
		  /bin/cat ../queue/"$file" } >> $f && log saved "$file" in $f
	done
}
</verb></tscreen>
This does the saving of intercepted messages into archive files.




<sect1>Rrouter.cf
<p>

Most of the address routing processing is done here.


<tscreen><verb>
provide rrouter
</verb></tscreen>

<tscreen><verb>
. fqdnalias.cf # Pick that set of tools into here!

envelopeinfo=(message-id "<$USER.interactive@$hostname>" now 0)

: ${UNRESOLVABLEACTION:='error unresolvable'}

relation -bt selfmatch selfmatch

rrouter (address, origaddr, A, plustail, domain) {
	local tmp tee didhostexpand priv nattr a
	# local seenuucp seenbitnet
	# seenuucp=false
	# seenbitnet=false
	didhostexpand="";
# echo "rrouter: address=$address, origaddr=$origaddr" >> /dev/tty

	tmp=$(fqdn_neighbour "$origaddr" "$address" $A) &&
		return $tmp

	address="$(condquote "$address")"

</verb></tscreen>
We have troublesome addresses coming here...
<tscreen><verb>
	#	"|pipe-program"
	#	"|quoted string"@domain
	#	"foo > faa"@domain
	#	"fii < fuu"@domain
	#	"foo @ faa"@domain
	#	"|foo @ faa"
<verb><tscreen>
and we want to do correct focusing...
<tscreen><verb>

	ssift "$address" in
	# Now make canonical
	'"'(.*)'"'<(.*)
		address="\1\2"			# defocus
		;;
	'"'(.*)'"'>(.*)
		address="\1\2"			# defocus
		break ;;
	([\'"'].*[\'"'])<(.*)
		address="\1\2" ;;		# defocus
	([\'"'].*[\'"'])>(.*)
		address="\1\2" ;;		# defocus
	# See that it does not start with a pipe ...
#	\|.+	# Looks like a pipe... Don't mutilate it!
#		break ;;
#	'"'[|].+	# Quoted pipe??   What the ...??
#		break ;;
	tfiss

	address=$(canonicalize "$address")

	ssift "$address" in
#	<in%>(.*)
#		return (((error vms-in-pros "in%\1" $A))) ;;
#	(.*)<@(.+)\.uucp>(.*)
#		seenuucp=true
#		address="\1$plustail<@\2>\3" ;;		# fix host.uucp!route
#	(.*)<@(.+)\.(bitnet|earn|netnorth)>(.*)
#		seenbitnet=true		# Strip off the (bitnet|netnorth|earn)
#		address="\1<@\2>\4" ;;		# fix host.bitnet!route
#	 handle special cases.....
#	\\(.)	return (((local - "$address" $A))) ;;
	@	# handle <> form???
		tmp=(local user postmaster $A)
		return $(routeuser $tmp "")
		;;
</verb></tscreen>

The following two are two approaches to the same problem, generally
speaking we should use the SECOND one, but your mileage may vary...
(Problems exist when WE are the target..)

<tscreen><verb>
#	(.*)<@\[(.)\]>(.*)
#		address="\1$plustail<@$(gethostbyaddr \2)>\3"
#		;;
	(.*)<@\[(.)\]>(.*)
		# numeric internet spec
		if [ $(selfmatch "\2") ]; then
			address="\1$plustail<@>\3"
			domain="@[\2]"
			plustail=""
		else
			return (((smtp "[\2]" "\1$plustail@$(gethostbyaddr \2)\3" $A)))
		fi
		;;
</verb></tscreen>

This is the end of the [1.2.3.4] address case...

<tscreen><verb>
	(.*)<@(.*)\.>(.*)
		address="\1$plustail<@\2>\3"
		plustail=""
		;;
</verb></tscreen>

Now massage the local info.

<tscreen><verb>
	(.*)<@(.*)($orgdomains)>(.*)
		address="\1$plustail<@\2$orgdomain>\4"
		domain="@\2$orgdomain"
		plustail=""
		;;
	<@(.*)>[:,](.+)@(.+)
		if [ $(deliver "\1") ]; then # Source routed to our name?
			return $(rrouter "\2$plustail@\3" "$origaddr" $A "" "")
		fi
		;;
	<@($orgdomains)>[:,](.+)@(.+)
		return $(rrouter "\2$plustail@\3" "$origaddr" $A "" "")
		;;	# strip organization
	(.+)<@(.+)>(.*)
		if [ $(deliver "\2") ]; then	# Do we handle this?
			address="\1$plustail<@>\3"
			domain="@\2"
			plustail=""
		elif [ "\2" = "$hostname" ]; then # Is it at local host?
			address="\1$plustail<@>\3" # (this is a backup test)
			domain="@\2"
			plustail=""
		fi ;;
	<@>.(.+)	# This plustail is propably wrong...
		return $(rrouter "\1$plustail" "$origaddr" $A "" "$domain") ;;	# try after route strip
	(.+)<@>	
		if [ -z "$domain" ]; then
			domain="$mydomain"
		fi
		return $(rrouter "\1$plustail" "$origaddr" $A "" "$domain") ;;	# strip trash & retry
	tfiss

#log "BITNET name=$bitnetname, address=$address"
	case $bitnetname in
	?*)	tsift "$address" in
		(.*)<@(.*)\.(bitnet|netnorth|earn)>(.*)
			address="\1<@\2>\4" ;;
			# Strip off the (bitnet|netnorth|earn)
		tfist
		;;
	esac
#log "BITNET name=$bitnetname, address=$address"

</verb></tscreen>

Resolve names to routes, get the actual channel name mostly from an external database.

<tscreen><verb>

	ssift "$address" in
	(.*)<@(.+)>(.*)	
#log "neighbourg test: domain: \2, addr: $address"
		address="\1$plustail@\2\3"
		plustail=""

</verb></tscreen>

If you want to have the SMARTHOST to pick the routing
for all non-local stuff, enable the following test case..

<tscreen><verb>

		# if [ "$SMARTHOST" ]; then
		#	return $(rrouter "$SMARTHOST!$(uucproute "$address")$plustail" "$origaddr" $A "" "$domain")
		# else
		#	return ((($UNRESOLVABLEACTION "$address" $A)))
		# fi


		#if [ x$seenbitnet = xtrue ]; then
		#	address="\1@\2.bitnet"
		#fi

		didhostexpand=$(hostexpansions "\2")

		for method in $protocols
		do
		   	tmp=$(${method}_neighbour "\2" "$address" $A) &&
				return $tmp
		done

		#if [ x$seenuucp = xtrue ]; then
		#	if [ "$UUCPACTION" != "" ]; then
		#		return ((($UUCPACTION "\1@\2.uucp" $A)))
		#	fi
		#	tmp=$(routes_neighbour "\2.uucp" "$address" $A) &&
		#		return $tmp
		#fi

		#if [ x$seenbitnet = xtrue ]; then
		#	if [ "$BITNETACTION" != "" ]; then
		#		return ((($BITNETACTION "\1@\2.BITNET" $A)))
		#	fi
		#fi


		if [ "$SMARTHOST" ]; then
			return $(rrouter "$SMARTHOST!$(uucproute "$address")" "$origaddr" $A "" "$domain")
		else
			return ((($UNRESOLVABLEACTION "$address" $A)))
		fi
		;;

	\\(.+)	# A back-quote prefixed userid (most likely)
		return $(rrouter "\1" "$origaddr" $A "$plustail" "")
		;;

	/.+	# file
</verb></tscreen>

Well, it could be a slash-notated X.400 address too..

<tscreen><verb>
		return (((local "file.$origaddr" "$address" $A)))
		;;
	\|.+	# pipe
		return (((local "pipe.$origaddr" "$address" $A)))
		;;
	:include:.+ # ":include:" -alias
</verb></tscreen>

We must test this here, because the file-path after
this prefix may have a dot.

<tscreen><verb>
		tmp=(local "$origaddr" "$address" $A)
		return $(routeuser $tmp "")
		;;
</verb></tscreen>

Ok, from now on if we don't have a domain set, we use <tt>&dollar;mydomain</tt>

<tscreen><verb>
	.*	if [ -z "$domain" ] ; then
			domain="@$mydomain"
		fi
		;;
	(.+\.[^+]+)(\+.+)  # Dotfull name with a plus!
		plustail="\2"
		address="\1"
</verb></tscreen>

Fall forward for the dotfull processing.

<tscreen><verb>
		;;
	.+\..+	# A dotfull name
		tmp="$(fullnamemap "$address")" && \
			return $(rrouter "$tmp" "$origaddr" $A "$plustail" "$domain")
		if [ $(newsgroup "$address") ]; then
			return (((usenet - "$address" $A)))
		fi
</verb></tscreen>

Okay... Not in our special fullname/newsgroup-files,
lets see if it is in the traditional one?

<tscreen><verb>
		if [ $(aliases "$address") ]; then
</verb></tscreen>

It can be found from the normal aliases,
run the alias processing.

<tscreen><verb>
			tmp=(local "$origaddr" "$address" $A)
			return $(routeuser $tmp "$domain")
		fi
		return (((error norealname "$address" $A)))
		return (((error nonewsgroup "$address" $A)))
		;;

	.*	# Now all the rest of the cases..
		tmp=(local "$origaddr" "$address$plustail" $A)
		return $(routeuser $tmp "$domain")
		;;
	tfiss
}	# end of rrouter

routes_spec (domain, address, A) {
	local tmp channel rscshost

	sift "$domain" in
#	(bsmtp3nd|bsmtp3|bitnet2|bitnet2deliver2)!(.)!(.)
	(bsmtp3nd|bsmtp3|bsmtp3nd|bsmtp3rfc|bsmtp3ndrfc)!(.)!(.)
		return (((\1 "\2@\3" "$address" $A))) ;;
	(defrt1)!(.)
		channel=\1
		rscshost=\2

		tmp="$(uucproute "$address")"
		sift "$tmp" in
		.+!([^!]+)!([^!]+)
</verb></tscreen>

We are trying to gateway through a DEFRT1 domain(!)

<tscreen><verb>
			#return (((error bitnetgw "$address" $A))) ;;
</verb></tscreen>

This will usually work anyway, sigh...

<tscreen><verb>
			return (((bsmtp3 "mailer@$rscshost" "\2@\1" $A))) ;;
		([^!]+)!([^!]+)
</verb></tscreen>

The destination domain is the next hop, so we're all happy.

<tscreen><verb>
			return ((($channel "\2@$rscshost" "\2@\1" $A))) ;;
		tfis
		;;
	ignore!.*
		break
		;;
	smtp!
		ssift "$address" in
		(.*)@(.+)
			return (((smtp "\2" "$address" $A)))
			;;
		tfiss
		;;
	dns!
		ssift "$address" in
		(.*)@(.+)
			return (((smtp "\2" "$address" $A)))
			;;
		tfiss
		;;
	(.?)!
		return ((("\1" - "$address" $A)))
		;;
	delay!(.)
</verb></tscreen>

NB! envelope info must also be defined in interactive mode.

<tscreen><verb>
		tmp="$(/bin/expr $(get envelopeinfo now) + "\1")"
		return (((hold "$tmp" "$address" $A))) ;;
	(.?)!([^!]+)
		return ((("\1" "\2" "$address" $A))) ;;
	(.?)!(.+)
		# BEWARE LOOPS
		return $(rrouter "\2!$(uucproute "$address")" "$address" $A "" "$domain")
		;;
	tfis
	return 1
}

uucproute (address) {
</verb></tscreen>

This function turns any address into a pure-! form.  It should not
call any other functions, since random other functions call it.
In particular it should not use rfc822route which itself uses
uucproute.

<tscreen><verb>
	sift "$address" in
	(.*)<(.*)>(.*)		address=\1\2\3 ;;		# defocus
	(.+!)@(.+)		address=\1$(uucproute "@\2") ;;
	(.+)([,:]@)(.+)		address=\1!\3 ; continue ;;
	:include:[^!]+		return $address ;;
	@(.+:)([^:]+)		address=\1$(uucproute "\2") ;;
	(.+):(.+)		address=\1!\2 ; continue ;;
</verb></tscreen>

This won't work properly for e.g. utzoo!bar@gpu.utcs.toronto.edu
because gpu.utcs also has an active uucp connection with utzoo.
It will work properly in other cases though, so if we have to guess...

<tscreen><verb>
	#([^!])!(.+)@(.+)	if [ $(ldotsys \1) ]; then
	#				address=\1!\3!\2
	#			else
	#				address=\3!\1!\2
	#			fi ;;
	(.+)!([^!]+)%([^!%]+)@(.+)	# route!a%b@c -> route!c!a@b
				address=\1!\4!\2@\3 ; continue ;;
	([^@]+)@(.+)		address=\2!\1 ;;
	@(.+)			address=\1 ;;
	(.+)!([^!]+)[%@](.+)	address=\1!\3!\2 ;;
	tfis
	return "$address"
}	# end of uucproute
</verb> </tscreen>  
<!-- app_listmgr.sgml -->
<sect>Using ZMailer with Mailinglist Managers
<p>Text to be inserted here.


   
<!-- app_newagnts.sgml -->
<sect>Adding new transport agents
<p>Text to be inserted here.
                                



<!-- app_datafmt.sgml -->
<sect>Internal File Data Formats
<p>
<sect1>Message File Format
<p>

As mentioned, the <em>router</em> picks up message files from a specific directory.
Normally, message file names can be arbitrary valid file names, and indeed
this is convenient when debugging.  However, because the <em>router</em> daemon
scans its own current directory, miscellaneous output from the <em>router</em>
process may show up in this directory (e.g. profiling data, or core dumps
(unthinkable as that is)).  Furthermore, it is useful to be able to hide
files from the <em>router</em> scanning (indeed the <em>router</em> may wish to do so
itself).

When the <em>router</em> process is scanning for message files then, it only
considers at file names that have a certain format.  Specifically, the
message file name must start with a digit.  This method was chosen to
accomodate the message file names, as generated by the standard submission
interface library routines, which will be strings of digits representing
the message file's inode number.

A message file contains three sections: the message envelope, the message
header, and the message body (in that order).  The message body is
separated from the previous sections by a blank line.  The message body may
be empty, and either of the message envelope or message header may be
empty.  The restriction on the latter situation, is that one of those
sections must contain destination information for the message.

The message envelope and the message header have very similar syntax.  The
only difference is that while the message header must adhere to RFC822, the
message envelope header fields are terminated by whitespace (` ') instead
of a colon (`:').  The semantics of the two message file sections is quite
different, and will be covered later.

<sect2>Envelope Header Lines
<p>

The message envelope headers are used to carry meta-information
about the message.  The goal is to carry transport-envelope 
information separate from message (RFC-822) headers, and body.
At first the message starts with a set of envelope headers 
(*-prefix denotes optional):

<tscreen><verb>
 *external \n
 *rcvdfrom %s@%s (%s) \n
 *bodytype %s \n
 *with %s \n
 *identinfo %s \n
</verb></tscreen>
 Either:
<tscreen><verb>
   from <%s> \n
</verb></tscreen>
 Or:
<tscreen><verb>
   channel error \n
 *envid %s \n
 *notaryret %s \n
</verb></tscreen>

Then for each recipient pairs of:
<tscreen><verb>
 *todsn [NOTIFY=...] [ORCPT=...] \n
 to <%s> \n
</verb></tscreen>

Just before the data starts, a magic entry:
<tscreen><verb>
 env-end \n
</verb></tscreen>

Then starts the message RFC-822 headers, and below it, the body.

The header fields recognized by ZMailer in the message envelope are:

<descrip>
<tag/<tt>bodytype <em>word</em></tt> / not used. Compatibility with the <em>sendmail</em> feature 
<tag/<tt>channel</tt> <em>word</em>/ sets the channel corresponding to the message origin(*), usually as ``channel error''
<tag/<tt>comment <bf>`string'</bf></tt> / arbitrary comment
<tag/<tt>env-end</tt>/ separator between the envelope and the RFC822 headers
<tag/<tt>env-eof</tt>/ alias to env-end
<tag/<tt>envid</tt> xtext/ ESMTP DSN ENVID value
<tag/<tt>external</tt>/ keyword indicating the external origin of a message
<tag/<tt>from</tt> `address'/ a source address(*)
<tag/<tt>fullname</tt> `phrase'/ sets the full name of the local sender
<tag/<tt>identinfo</tt> `string'/ The SMTP server's ident lookup result, this does not guarantee anything about the sender though.
<tag/<tt>loginname</tt> `local-part'/ requests using this mail id for the local sender
<tag/<tt>notaryret </tt> <em>word</em>/ ESMTP DSN RET=<em>word</em>, either ``FULL'' ``HPRS''
<tag/<tt>rcvdfrom</tt> `domain'/ sets the host the message was received from(*)
<tag/<tt>to</tt> `address-list'/ a destination address list
<tag/<tt>todsn</tt> `phrase'/ ESMTP DSN recipient parameters. Note: this must be before the recipient ``To'' line for which this gives the extra parameters.
<tag/<tt>user</tt> `local-part'/ sets the user the message was received from(*)
<tag/<tt>verbose</tt> zzz/ zzz
<tag/<tt>via</tt> `word'/ for RFC822 Received: header to be generated
<tag/<tt>with</tt> `word'/ for RFC822 Received: header to be generated
</descrip>

The (*)'s beside the descriptions indicate this is a privileged field.
That is, the action will only happen if ZMailer trusts the owner of the
message file (*Note Security: security.).  As with a normal RFC822 header,
other fields are allowed (though they will be ignored), and case is not
significant in the field name.  The <em>router</em> will do appropriate checks for
the fields that require it.

With this knowledge, we can now appreciate the minimal message file:

<tscreen><verb>
     --------------------
     to bond
     
     --------------------
</verb></tscreen>

This will cause an empty message to be sent to <tt>bond</tt>.  A slightly more
sophisticated version is:

<tscreen><verb>
     --------------------
     from m
     to bond
     via courier
     env-end
     From: M
     To: Bond
     Subject: do get a receipt, 007!
     
     You are working for the Government, remember?
     --------------------
</verb></tscreen>

Notice that there is no delimiter between the message envelope and the
message header.  A more sophisticated example in the same vein:

<tscreen><verb>
     --------------------
     from ps/d-ops
     to <007@sis.mod.uk>
     env-end
     From: M <d-ops@sis.mod.uk>
     Sender: Moneypenny <ps/d-ops@sis.mod.uk>
     To: James Bond <007@sis.mod.uk>
     Subject: where are you???!
     Classification: Top Secret
     Priority: Flash
     
     We have another madman on the loose.  Contact "Q" for usual routine.
     --------------------
</verb></tscreen>

If the <tt>Classification</tt> header is paid attention to in ZMailer, this
requires that the <em>router</em> recognize it in the message header, and take
appropriate action.  In general the <em>router</em> can extract most of the
information in the message header, and make use of it if the information is
lacking in the envelope.  The envelope headers in the above message are
superfluous, since the same information is contained in the message header.
Using the following envelope headers would be exactly equivalent to using
the ones shown above (assuming the local host is <tt>sis.mod.uk</tt>):

<tscreen><verb>
     --------------------
     From Moneypenny <ps/d-ops@sis.mod.uk>
     To James Bond <007@sis.mod.uk>
     ...
     --------------------
</verb></tscreen>

ZMailer will extract the appropriate address information from whatever the
field values are, as long as they obey the defined syntax (indicated in the
list of recognized envelope fields above).  ZMailer will complain in case
of unexpected errors in the envelope headers.

The message body is not interpreted by ZMailer itself.  As far as the
<em>router</em> is concerned, it can be arbitrary data.  However, certain Transport
Agents may require limitations on the message body data. For example, the
SMTP only deals with ASCII data with a small guaranteed line length.




<sect1>Message Control File
<p>
A message control file is a file created by the <em>router</em> to contain all the
information necessary for delivery of a message submitted in a
corresponding message file.  It is interpreted by the Scheduler, which
needs to know at all times which messages are pending to go where, and how.
It is also interpreted by one or more Transport Agents, possibly
concurrently, that extract the delivery information relevant to their
purpose.

The concurrency aspect means that the Transport Agents must cooperate on a
locking protocol to ensure that delivery to a particular destination is
attempted by only one Transport Agent at a time, and a status protocol to
ensure unique success or failure of delivery for each destination.  There
are potentially many ways to implement such protocols, but, in the spirit
of simplicity, ZMailer uses a control file as a form of shared memory.
Specific locations within each control file are reserved for flags that
indicate a specific state for their associated destination address.  The
rest is taken care of by the I/O semantics when multiple processes update
the same file.

Apart from necessary envelope and control information, a control file also
contains the new message header for the message, which contains the header
addresses as rewritten by the <em>router</em>.  Since a message may have several
destinations with incompatible address format requirements, there may be
several corresponding groups of message headers.  This will be illustrated
by the sample control file shown in the following subsection.

<sect2>Format
<p>
A control file consists of a sequence of fields.  Each field starts at the
beginning of a line (i.e. at byte 0 or after a Newline), and is identified
by the appearance of a specific character in that location.  This id
character is normally followed by a byte containing a tag value (semaphore
flag), followed by the field value.

Here is a simple control file produced by a test message, just before it
was removed by the Scheduler:

<tscreen><verb>
     --------------------
     i 24700
     o 72
     l <88Jan10.003129est.24700@bay.csri.toronto.edu>
     e Rayan Zachariassen <rayan>
     s local - rayan
     r+local - rayan 2003
     m
     Received: by bay.csri.toronto.edu id 24700; Sun, 10 Jan 88 00:31:29 EST
     From:   Rayan Zachariassen <rayan>
     To:     rayan, rayan@ephemeral
     Subject: a test
     Message-Id: <88Jan10.003129est.24700@bay.csri.toronto.edu>
     Date:   Sun, 10 Jan 88 00:31:24 EST
     
     s local - rayan@bay.csri.toronto.edu
     r+smtp ephemeral.ai.toronto.edu rayan@ephemeral.ai.toronto.edu 2003
     m
     Received: by bay.csri.toronto.edu id 24700; Sun, 10 Jan 88 00:31:29 EST
     From:   Rayan Zachariassen <rayan@csri.toronto.edu>
     To:     rayan@csri.toronto.edu, rayan@ephemeral.ai.toronto.edu
     Subject: a test
     Message-Id: <88Jan10.003129est.24700@bay.csri.toronto.edu>
     Date:   Sun, 10 Jan 88 00:31:24 EST
     
     --------------------
</verb></tscreen>

The id character values are defined in the <tt>mail.h</tt> system header file,
which currently contains:

<tscreen><verb>
     
#define _CF_MESSAGEID   'i'     /* inode number of file containing message */
#define _CF_BODYOFFSET  'o'     /* byte offset into message file of body */
#define _CF_BODYFILE    'b'     /* alternate message file for new body */
#define _CF_SENDER      's'     /* sender triple (channel, host, user) */
#define _CF_RECIPIENT   'r'     /* recipient n-tuple, n >= 3 */
#define _CF_DSNRETMODE  'R'     /* DSN message body return control */
#define _CF_XORECIPIENT 'X'     /* one of XOR set of recipient n-tuples */
#define _CF_RCPTNOTARY  'N'     /* DSN parameters for previous recipient */
#define _CF_DSNENVID    'n'     /* DSN 'MAIL FROM<> ENVID=XXXX' data */
#define _CF_ERRORADDR   'e'     /* return address for error messages */
#define _CF_DIAGNOSTIC  'd'     /* diagnostic message for ctlfile offset */
#define _CF_MSGHEADERS  'm'     /* message header for preceeding recipients */
#define _CF_LOGIDENT    'l'     /* identification string for log entries */
#define _CF_OBSOLETES   'x'     /* message id of message obsoleted by this */
#define _CF_VERBOSE     'v'     /* log file name for verbose log (mail -v) */
#define _CF_TURNME      'T'     /* trigger scheduler to attempt delivery now */
#define _CF_RCVFROM     'F'     /* Where-from we are coming ? */               

</verb></tscreen>

There is one field per line, except for <tt>_CF_MSGHEADERS</tt> which  has
some special semantics described below.  The following describes the fields
in detail:

 <tt>i</tt>     
     This field identifies the message file corresponding to this control
     file.  It is the name of the message file in the <tt>QUEUE</tt>
     directory (<tt>&tilde/queue</tt>).  This is typically the same as the
     inode number for that file, but need not be.  It is used by Transport
     Agents when copying the message body, and by the Scheduler when
     unlinking the file after all the destination addresses have been
     processed.  For example:
     
<tscreen><verb>
          i 21456
</verb></tscreen>
     
 <tt>o</tt>     
     Specifies the byte offset of the message body in the message file.  It
     is used by Transport Agents in order to copy the message body quickly,
     without parsing the message file.  For example:

<tscreen><verb>     
          o 466
</verb></tscreen>

 <tt>b</tt>     
     Alternate message file for new body.
  
 <tt>e</tt>     
     Gives an address to which delivery errors should be sent.  The address
     must be an RFC822 mailbox.  For example:
     
<tscreen><verb>
          e "Operations Directorate" <d-ops@sis.mod.uk>
</verb></tscreen>
     
 <tt>l</tt>     
     The field value is an uninterpreted string which should prefix all log
     messages and accounting records associated with this message.  This
     value is typically the message id string.  For example:
     
<tscreen><verb>
          l <88Jan6.103158gmt.24694@sis.mod.uk>
</verb></tscreen>

 <tt>s</tt>     
     This field specifies an originator (sender) address triple, in the
     sequence: previous channel, previous host, return address.  It remains
     the current sender address until the next instance of this field.
     Since there can only be one sender of a message, multiple instances of
     the field will correspond to different return address formats as
     produced by the <tt>crossbar</tt> algorithm in the <em>router</em>.
     For example:
     
<tscreen><verb>
          s smtp sis.mod.uk @lab.sis.mod.uk:q@deadly-sun.lab.sis.mod.uk
          s uucp sisops lab.sis.mod.uk!deadly-sun.lab.sis.mod.uk!q
</verb></tscreen>

 <tt>r</tt>     
     This field specifies a destination (recipient) address triple, in the
     sequence: next channel, next host, address for next host.  Optional
     information to be passed to the Transport Agent may be placed after the
     mandatory fields; this currently refers to the delivery privilege of the
     destination address.  Since the optional values of this field are only
     interpreted by the Transport Agent, changes in what the <em>router</em> writes
     must be coordinated with the code of the Transport Agents that might
     interpret this field.  For example:
     
<tscreen><verb>
          r local - bond 0
          r uucp uunet sisops!bond -2
</verb></tscreen>

 <tt>R</tt>
     DSN message body return control.

<tt>X</tt>
     One of XOR set of recipient n-tuples.

<tt>N</tt>
     DSN parameters for previous recipient.

<tt>n</tt>
     DSN <tt>MAIL FROM&lt;&gt; ENVID=XXXX</tt> data.

 <tt>m</tt>     
     Apart from a message body, a Transport Agent needs the message headers
     to construct the message it delivers.  These message headers are
     stored as the value of this field.  Since message headers obviously
     can span lines, the syntax for this field is somewhat different than
     for the others.  The field id is immediately followed by a newline,
     which is followed by a complete set of message headers.  These are
     terminated (in the usual fashion) by an empty line, which also
     terminates this field.  In the following example, the last line of
     text is followed by an empty line, after which another field may
     start:
     
<tscreen><verb>
          m
          From: M
          To: Bond
          Subject: do get a receipt, 007!
</verb></tscreen>
     
 <tt>d</tt>     
     This field is <bf>not</bf> written by the <em>router</em>.  It is written by the
     Scheduler or transport agents to remember errors associated with specific addresses. The
     field value has two parts, the first being the byte offset in the
     control file of the destination (recipient) address causing the error,
     and the rest of the line being an error message.  The Transport Agents
     discover these errors and report them to the Scheduler.  The Scheduler
     will collect them and report them to the error return address (if any)
     after all the destinations have been processed.
     For example:
<tscreen><verb>
          d 878 No such local user: 'bond'.
</verb></tscreen>     

<tt>x</tt>
     Message id of message obsoleted by this.

<tt>v</tt>
     Log file name for verbose log (<tt>mail -v</tt>).

<tt>T</tt>
     Trigger scheduler to attempt delivery now.

<tt>F</tt>
     Where-from we are coming ?               

It should be noted, that in sender and recipient fields the first two field
values (channel and host) cannot contain embedded spaces, but the third
field value (the address) may.  Therefore, in the presence of extra fields,
parsing within Transport Agents must be cautious and not assume that an
address does not contain spaces.

As mentioned, the second byte of most fields are used for concurrency
control and status indication.  This tag byte can contain several values
that indicate current or previous activity.  The fields where this is
relevant are the destination (recipient) address and diagnostic fields.
The tag values are defined in the `mail.h' file mentioned previously, as
follows:
<tscreen><verb>
     #define _CFTAG_NORMAL ' ' /* what the router sets it to be */
     #define _CFTAG_LOCK   '~' /* that line is being processed, lock it */
     #define _CFTAG_OK     '+' /* positive outcome of processing */
     #define _CFTAG_NOTOK  '-' /* something went wrong */
     #define _CFTAG_DEFER  _CFTAG_NORMAL /* try again later */
</verb></tscreen>
The extract above is self-explanatory.

A message control file will normally contain a preamble that specifies
information about the associated message file, the message body offset, an
error return address, and a log entry tag.  After this comes a repeated
sequence of: sender address field, recipient address fields, and the
message header corresponding to these recipients.  After as many of these
groups as are necessary, any diagnostic fields will be appended to the end
of the control file.  The restrictions on the sequence of addresses and
message headers, are that a sender address field must precede any recipient
address field, and a recipient address field must (immediately) precede any
message header field, and no sender or recipient addresses may follow the
last message header field.


<sect1>Scheduler and Transport Agent Protocol
<p>
                                
The transport agent interface follows a master-slave model,
where  the  TA  informs the scheduler that it is ready for
the work, and then the scheduler sends it one job 
description,  and  waits  for diagnistics.  Once the job is 
finished, the TA notifies the scheduler that it is ready for
a new job.

A short sample session looks like this:
<tscreen><verb>
(start the transport agent)
#hungry --> (TA to scheduler)
spoolid\thostspec <-- (scheduler to TA)
diagnostics --> (TA to scheduler)
#hungry <-- (scheduler to TA)
...
</verb></tscreen>
Normal diagnostic output is of the form:
<tscreen><verb>
id/offset\tnotarydata\tstatus message
</verb></tscreen>
where
<descrip>
<tag/<tt>id</tt>/ is the inode number of the message file,
<tag/<tt>offset</tt>/ is a byte offset within its control file where the address
being  reported	on  is kept,
<tag/<tt>notarydata</tt>/ is a <tt>Ctrl-A</tt> separated triplet is delivery-status-notification
information for  the message, 
<tag/<tt>status</tt>/ is one of <tt>ok</tt>, <tt>error</tt>, <tt>deferred</tt>, or <tt>retryat</tt>,
<tag/<tt>message</tt>/ is  descriptive	 text  associated
with  the  report.   The text is terminated by a linefeed.
</descrip>

Any other format (as might be produced by subprocesses) is
passed  to  standard  output  for logging in the scheduler
log. The <tt>retryat</tt> response will assume the first word  of
the text is a numeric parameter, either an incremental
time in seconds if prefixed by `+', or otherwise an absolute
time in seconds since <tt>epoch</tt>.

The exit status is a code from <tt>&lt;sysexits.h&gt;</tt>.


<sect1>Database File Formats
<p>
<sect2>Aliases File
<p>

<tscreen><verb>
postmaster: root
postoffice: root
MAILER-DAEMON: root
mailer:     postmaster
postmast:   postmaster

proto:	postmaster
sync:	postmaster
sys:	postmaster
daemon: postmaster
bin:	postmaster
uucp:	postmaster
ingress: postmaster
audit:	postmaster

autoanswer: "|@MAILBIN@/autoanswer.pl"

nobody: /dev/null
no-one: /dev/null
junk-trap: /dev/null

#test-gw: "|/..."
#test.gw: "|/..."
</verb></tscreen>

Doing expansion lists in <em>sendmail</em> style is not suggested, although
we certainly can do it.  There is a better mechanism in the ZMailer
to handle simple feats like these that <em>sendmail</em> systems do by placing
the file containing recipient addresses into the directory  
<tt>&dollar;MAILVAR/lists/</tt>.
This directory must have protection of 2775 or stricter, and the listfile
must have protection of 664 or stricter for *-request/owner-*/*-owner
auto-aliases to work. -- but to <em>sendmail</em> style lists:

<tscreen><verb>
listname: "/usr/lib/sendmail -fowner-listname listname-dist"
owner-listname: root # Well, what would you suggest for a sample ?
listname-owner: owner-listname
listname-request: root
listname-dist: ":include:/dev/null"
</verb></tscreen>


<!-- app_ssl.sgml -->
<sect>S/SL Language
<p>The information in this appendix is based on 
``Specification of S/SL: Syntax/Semantic Language'' by 
J.R. Cordy and R.C. Holt, December 1979 (Revised March 1980).
Copyright (C) 1979, 1980 by the  University of  Toronto.

This appendix describes the S/SL language which is used
within several scanners of the router system; rfc-822
object token scanner, and zmsh script language scanner
to name the most important ones.

S/SL is a programming language developed at
the Computer Systems Research Group,
University of Toronto as a tool for constructing compilers.
It has been used to implement scanners, parsers, semantic
analyzers, storage allocators and machine code generators.
S/SL  has  been	 used  to implement compilers for Euclid, PT
Pascal and Speckle, a PL/1 subset.

<sect1>Introduction
<p>
S/SL is a procedure-based variable-free programming 
language in which the program logic is  stated  using  a  small
number	of  simple  control constructs.	 It accesses data in
terms of a set of operations organized into  data-management
modules	 called	 mechanisms.   The interface to these 
mechanisms is defined in S/SL but their implementation is  hidden
from the S/SL program.

S/SL has one input stream and one output stream, each of
which is strictly sequential.  These streams  are  organized
into ``tokens'' each of which is read and written as a unit.
An auxiliary output stream for	error  diagnostics  is	also
provided.

<sect1>Identifiers, Strings and Integers
<p>
An  S/SL identifier may consist of any string of up to 50
letters, digits and underscores (_) beginning with a letter.
Upper  and  lower  case	 letters are considered identical in
S/SL, hence <tt>aa</tt>, <tt>aA</tt>, <tt>Aa</tt> and <tt>AA</tt> 
all represent the same identifier.  <tt>INPUT</tt>, <tt>OUTPUT</tt>, 
<tt>ERROR</tt>, <tt>TYPE</tt>, <tt>MECHANISM</tt>, <tt>RULES</tt>, 
<tt>DO</tt>, <tt>OD</tt>, <tt>IF</tt>, <tt>FI</tt>, <tt>END</tt> 
and their various lower case forms are  keywords
of  S/SL and must not be used as identifiers in an S/SL 
program.

An S/SL string is any sequence of characters not  
including a quote surrounded by quotes (").

Integers  may be signed or unsigned and must lie within a
range defined by  the  implementation.	 For  example,	this
range could be -32767 to 32767 on the PDP-11.

Identifiers, keywords,  strings  and  integers  must not
cross line boundaries.	Identifiers, keywords  and  integers
must not contain embedded blanks.

<sect1>Comments
<p>A  comment consists of the character ``%'' (which is not in
a string) and the characters to the right of it on a  source
line.

<sect1>Character Set
<p>Since  not all of the special characters used in S/SL are
available on all machines,  the	 following  alternatives  to
special characters are allowed.
<itemize>
<item><tt>!</tt> for <tt>|</tt>
<item><tt>DO</tt> for <tt>{</tt>
<item><tt>OD</tt> for <tt>}</tt>
<item><tt>IF</tt> for <tt>[</tt>
<item><tt>FI</tt> for <tt>]</tt>
</itemize>

<sect1>Source Program Format
<p>
S/SL programs are free format; that is, the identifiers,
keywords, strings, integers  and  special  characters  which
make  up  an  S/SL program may be separated by any number of
blanks, tab characters, form feeds and	source	line  bound-
aries.

<sect1>Notation
<p>The	 following  sections  define  the  syntax  of  S/SL.
Throughout the following, <tt>{item}</tt> means zero or more  of the
item,  and <tt>[item]</tt> means the item is optional.  The abbreviation 
<tt>id</tt> is used for identifier.

<sect2>Programs
<p>An S/SL program consists of a set of definitions followed
by a set of rules.

A program is:
<tscreen><verb>
	[inputDefinition]		[outputDefinition]
	[inputOutputDefinition]
	[errorDefinition]		{typeOrMechanismDefinition}
	RULES				{rule}		   
	END
</verb></tscreen>

<sect2>Input and Output Definitions
<p>An <tt>inputDefinition</tt> is:
<tscreen><verb>
	INPUT	":"			 {tokenDefinition} ";"
</verb></tscreen>

An <tt>outputDefinition</tt> is:
<tscreen><verb>
	OUTPUT  ":"			 {tokenDefinition} ";"
</verb></tscreen>

An <tt>inputOutputDefinition</tt> is:
<tscreen><verb>
	 INPUT OUTPUT ":"	 {tokenDefinition} ";"
</verb></tscreen>

A <tt>tokenDefinition</tt> is:
<tscreen><verb>
	 id [string] ["=" tokenValue]
</verb></tscreen>

The <tt>inputDefinition</tt> section defines the input  tokens  to
the  S/SL program.  The <tt>outputDefinition</tt> section defines the
output tokens of  the  program.	  The  <tt>inputOutputDefinition</tt>
section defines those tokens which are both input tokens and
output tokens of the program.  Tokens already defined in the
<tt>inputDefinition</tt> or  <tt>outputDefinition</tt> sections
must not be
redefined in the <tt>inputOutputDefinition section.</tt>

The optional string which may be given in a <tt>tokenDefinition</tt>
is  a synonym for the token identifier and can be used
in place of the identifier anywhere in the S/SL program.

Each input and output token is assigned an integer  value
for  use  in  the  implementation of the S/SL program.	This
value may be optionally specified in  each  <tt>tokenDefinition</tt>.
The <tt>tokenValue</tt> may  be  specified  as an integer or as the
value of any previously defined identifier  or	string.	  If
omitted,  the value assigned to the token is the value associated with 
the previous token in the class plus one. The
default	 value associated with the first input token and the
first output token is zero.  The  default  value  associated
with the first input-output token is the maximum of the last
token defined in the <tt>inputDefinition</tt> section  and  the	last
token  defined in the <tt>outputDefinition</tt> section.	 In this way
the  default  input-output  token  values  are	unique	with
respect to both input tokens and output tokens.

<sect2>Error Signals
<p>An <tt>errorDefinition</tt> is:
<tscreen><verb>
	 ERROR	":"			  {errorSignalDefinition} ";"
</verb></tscreen>

An <tt>errorSignalDefinition</tt> is:
<tscreen><verb>
	 id ["=" errorValue]
</verb></tscreen>

Each <tt>errorSignalDefinition</tt> defines an error signal  which
can be signalled by the S/SL program.  An integer error code
value is associated with each errorId for use in the  
implementation of the S/SL program.	This value may be optionally
specified in each <tt>errorSignalDefinition</tt>.  The <tt>errorValue</tt> may
be specified as an integer or as the value of any previously
defined identifier or string.  The default value  associated
with an error signal is the value associated with the 
previous error signal plus one.  The default value for the  first
error signal is 10 (errors 0 to 9 are reserved for S/SL system use).

<sect2>Type and Mechanism Definitions
<p>
Type and mechanism definitions may be grouped and  inter-
mixed  to reflect the association of types and the operation
definitions which use them.

A <tt>typeOrMechanismDefinition</tt> is one of:
<itemize>
<item><tt>typeDefinition</tt>
<item><tt>mechanismDefinition</tt>
</itemize>

<sect3>Types.
<p>A <tt>typeDefinition</tt> is:
<tscreen><verb>
	 TYPE id ":"			  {valueDefinition} ";"
</verb></tscreen>

A <tt>valueDefinition</tt> is:
<tscreen><verb>
	 id ["=" value]
</verb></tscreen>

Each <tt>typeDefinition</tt> defines a type of values for  use  as
the  parameter	or result type of a semantic operation or as
the result type of a rule.

Each <tt>valueDefinition</tt> defines a <tt>valueId</tt> in the  type. An
integer value is associated with each <tt>valueId</tt> for use in the
implementation of the  S/SL  program.	This  value  may  be
optionally specified in each <tT>valueDefinition</tt>.  The value may
be specified as an integer or as the value of any previously
defined identifier or string.  The default value assigned to
a value identifier is the value associated with the previous
value  identifier  plus	 one.	The default value associated
with the first <tt>valueDefinition</tt> in a type is zero.

<sect3>Mechanisms.
<p>
A <tt>mechanismDefinition</tt> is:
<tscreen><verb>
	 MECHANISM    id    ":"		{operationDefinition} ";"
</verb></tscreen>
Each <tt>mechanismDefinition</tt>  defines  the  set	 of semantic
operations associated with a semantic mechanism.  The 
<tt>mechanismId</tt> itself is unused in the S/SL program.  However, 
operation identifiers associated with a mechanism are by 
convention expected to begin with the mechanism identifier.

An <tt>operationDefinition</tt> is one of:
<enum>
<item><tt>id</tt>
<item><tt>id "(" typeId")"</tt>
<item><tt>id ">>" typeId</tt>
<item><tt>id "(" typeId ")" ">>" typeId</tt>
</enum>

Each <tt>operationDefinition</tt> defines  a  semantic operation
associated with the mechanism.
<itemize>
<item>Form 1 defines  an	 update	 semantic  operation,  which
causes an update to the semantic data structure.

<item>Form 2 defines a parameterized update operation, which
uses the parameter value to update the semantic data  
structure.  The <tt>typeId</tt> gives the type of the parameter and can be
any previously defined type.

<item>Form 3  defines  a	 choice	 semantic  operation,  which
returns	 a  result  value obtained from the current state of
the semantic mechanism, which is used as the selector  in  a
semantic  choice.   The	 <tt>typeId</tt> gives the type of the result
and can be any previously defined type.

<item>Form 4 defines a parameterized choice  operation. The
first <tt>typeId</tt> gives the parameter type, the second the result
type.  Each can be any previously defined type.
</itemize>
Choice operations  (forms 3 and	4 above)  may  be
invoked only as the selector in a semantic choice.

<sect2>Rules
<p>
A rule is one of:
<enum>
<item><tt>id	  ":"		{action} ";"</tt>
<item><tt>id ">>"  typeId  ":"	{action} ";"</tt>
</enum>

The	rules  define  the  subroutines and functions of the
S/SL program.  Rules may call one  another  recursively.   A
rule  need  not	 be defined before it is used.	Execution of
the program begins with the first rule.
<itemize>
<item>Form 1 defines a procedure rule which  can	 be  invoked
using a call action.

<item>Form 2 defines  a  choice rule which returns a result
value  of  the	specified  type.   The	<tt>typeId</tt>	can  be	 any
previously  defined  type.  Choice rules may only be invoked
as the selector in a rule choice.
</itemize>
<sect2>Actions
<p>
An action is one of the following:
<enum>
<item><verb>inputToken</verb>
<item><verb>"." outputToken</verb>	   
<item><verb>"#" errorId</verb>
<item><verb>"{" {action} "}"</verb>
<item><verb>">"</verb>
<item><verb>"[" { "|" inputToken {","    inputToken} ":" {action} }
                [ "|" "*" ":" {action} ] "]"</verb>
<item><verb>"@" procedureRuleId</verb>
<item><verb>">>"</verb>
<item><verb>"[" "@" choiceRuleId {"|" valueId {"," valueId} ":" {action} }
                ["|" "*" ":" {action} ] "]"</verb>		  
<item><verb>">>" valueId</verb>
<item><verb>updateOpId</verb>
<item><verb>parameterizedUpdateOpId "(" valueId ")"</verb>
<item><verb>"[" choiceOpId {"|"	valueId {"," valueId} ":" {action} }
                ["|" "*" ":" {action} ] "]"</verb>
<item><verb>"["	parameterizedChoiceOpId "(" valueId ")"
                "|" valueId {"," valueId} ":" {action} }
                ["|" "*" ":" {action} ]	"]"</verb>
</enum>

<itemize>
<item>Form 1 is an input action.	 The next input token is  to
be  accepted  from  the	 input stream.	If it is not the one
specified, a syntax error is flagged.  The <tt>inputToken</tt> may be
an <tt>inputTokenId</tt>, an <tt>inputOutputTokenId</tt>, an <tt>inputTokenString</tt>,
an <tt>inputOutputTokenString</tt>, or  a  question  mark  (<tt>?</tt>).
The question  mark	is  a  special token which matches any input
token.

<item>Form 2 denotes emission of an output token to the	output  stream.   
The <tt>outputToken</tt> may be an <tt>outputTokenId</tt>, an
<tt>inputOutputTokenId</tt>, an <tt>outputTokenString</tt> or an
<tt>inputOutputTokenString</tt>.

<item>Form 3 denotes the emission of the specified error signal to the error stream.

<item>Form 4 is a cycle or loop.	 Execution  of	the  actions
inside	the  cycle  is repeated until one of its cycle exits
(form 5) or a return (forms 8 and 10)  is	encountered.
A  cycle  exit	causes	execution  to continue following the
nearest enclosing cycle.   The	cycle  exit  action  is	 not
allowed outside of a cycle.

<item>Form 6 is an input token choice.  The next token in the
input stream is examined and execution	continues  with	 the
first  action  in  the	alternative labelled with that input
token.	The matched input token is accepted from  the  input
stream.

Each <tt>inputToken</tt> label  can  be  an <tt>inputTokenId</tt>,  an
<tt>inputOutputTokenId</tt>, an <tt>inputTokenString</tt> or an 
<tt>inputOutputTokenString</tt>.  A label can not be repeated nor appear 
on more than one alternative.

The alternative labelled with an  <tt>*</tt>  is  the  otherwise
alternative.   If the next input token does not match any of
the alternative labels of the  choice,	execution  continues
with  the first action in the otherwise alternative.  If the
otherwise alternative is  taken,  the  input  token  is	 not
accepted  from	the  input  stream,  but remains as the next
input token.  After execution  of  the	last  action  in  an
alternative of the choice, execution continues following the
choice.

If the next input token does not match any of the  
alternative	labels	and  no	 otherwise alternative is present, a
syntax error is flagged.  For parsers written in  S/SL,	 the
default	 error	handling  strategy  is	to repeat the choice
after modifying the input stream such that  the	 next  input
token  matches	the  first alternative.	 For compiler phases
other than parsers, continued execution	 is  undefined	(the
implementation aborts).

<item>Form 7 is a call to a procedure rule.  Execution 
continues at the first action in the specified rule.  When 
execution	of the called rule is completed, either by executing
the last action in the rule  or	 by  encountering  a  return
action	(form 8), execution is resumed following the call.

<item>Form 8 is a return action.	 It causes a return from the
procedure  rule	 in  which it appears.	A procedure rule may
return explicitly by executing a return action or implicitly
by  reaching the end of the rule.  A procedure rule must not
contain a valued return (form 10).

<item>Form 9 is a rule choice.  The specified choice rule  is
called	and  returns  a	 value	by executing a valued return
action (form 10).  The returned value is  used	 to  make  a
choice	similar	 to  an input token choice (form 6 above).
Execution continues with the first action of the alternative
whose  label  matches  the  returned  value.  If none of the
alternative labels matches the value, the otherwise 
alternative  is  taken.   Following execution of the last action in
the chosen alternative, execution  continues  following	 the
choice.

Each	 alternative  label in a rule choice must be a value
of the result type of the choice rule.	A label can  not  be
repeated nor appear on more than one alternative.

<item>Form 10 is a valued return action.	 The specified value
is returned as the result of the choice rule  in  which	 the
action appears.	 The value must be of the result type of the
choice rule.  A choice rule may return only by	executing  a
valued return action.  A choice rule must not return 
implicitly by reaching the end of the rule.  It must not contain a
non-valued return (form 8).

<item>Form 11 is the invocation of an update semantic 
operation.  Similarly, form 12 is the invocation of a 
parameterized  update  operation.  The parameter value, which must be
of the operation's parameter type, is supplied to the  
invocation of the operation.

<item>Form 13 is  a  semantic  choice.	The specified choice
semantic operation is invoked and the returned value used to
make  a	 choice	 similar  to an input token choice (form 6
above).	 Execution continues with the first  action  of	 the
alternative whose label matches the returned value.  If none
of the alternative labels matches the value,  the  otherwise
alternative  is	 taken.	  Following  execution	of  the last
action in the chosen alternative, execution  continues	
following	the  choice.  Similarly, form 14 is a parameterized
semantic choice.  The parameter value, which must be of	 the
operation's parameter type, is provided to the invocation of
the choice operation.
</itemize>
Each alternative label in a semantic	 choice	 must  be  a
value  of  the result type of the choice operation.  A label
can not be repeated nor appear on more than one alternative.

If the returned value in a rule choice or semantic choice
does not match any of the alternative labels and  no  
otherwise  alternative  is  present, continued execution is 
undefined (the implementation aborts).

<sect2>The Syntax of S/SL
<p>
A program is:
<tscreen><verb>
     [inputDefinition]     [outputDefinition]
     [inputOutputDefinition]
     [errorDefinition]     {typeOrMechanismDefinition}
     RULES		   {rule}		   
     END
</verb></tscreen>

An <tt>inputDefinition</tt> is:
<tscreen><verb>
     INPUT ":"			 {tokenDefinition} ";"
</verb></tscreen>

An <tt>outputDefinition</tt> is:
<tscreen><verb>
     OUTPUT ":"			 {tokenDefinition} ";"
</verb></tscreen>

An <tt>inputOutputDefinition</tt> is:
<tscreen><verb>
     INPUT OUTPUT ":"		 {tokenDefinition} ";"
</verb></tscreen>

A <tt>tokenDefinition</tt> is:
<tscreen><verb>
     id [string] ["=" tokenValue]
</verb></tscreen>

An <tt>errorDefinition</tt> is:
<tscreen><verb>
     ERROR	":"	  {errorSignalDefinition} ";"
</verb></tscreen>

An <tt>errorSignalDefinition</tt> is:
<tscreen><verb>
     id ["=" errorValue]
</verb></tscreen>

A <tt>typeOrMechanismDefinition</tt> is one of:
<enum>
<item><tt>typeDefinition</tt>
<item><tt>mechanismDefinition</tt>
</enum>

A <tt>typeDefinition</tt> is:
<tscreen><verb>
     TYPE id ":"		  {valueDefinition} ";"
</verb></tscreen>

A <tt>valueDefinition</tt> is:
<tscreen><verb>
     id ["=" value]
</verb></tscreen>

A <tt>mechanismDefinition</tt> is:
<tscreen><verb>
     MECHANISM    id    ":" {operationDefinition} ";"
</verb></tscreen>

A rule is one of:
<enum>
<item><verb>id ":" {action} ";"</verb>
<item><verb>id ">>" typeId  ":" {action} ";"</verb>
</enum>

An action is one of the following:
<enum>
<item><verb>inputToken</verb>
<item><verb>"." outputToken</verb>
<item><verb>"#" errorId</verb>
<item><verb>"{" {action} "}"</verb>
<item><verb>">"</verb>
<item><verb>"["	{"|" inputToken {"," inputToken} ":" {action} }
                ["|" "*" ":" {action} ] "]" </verb>
<item><verb>"@" procedureRuleId</verb>
<item><verb>">>"</verb>	     
<item><verb>"[" "@" choiceRuleId {"|" valueId {"," valueId} ":" {action} }
                ["|" "*" ":" {action} ] "]" </verb>
<item><verb>">>" valueId</verb>
<item><verb>updateOpId</verb>
<item><verb>parameterizedUpdateOpId "(" valueId ")"</verb>
<item><verb>"[" choiceOpId {"|" valueId {"," valueId} ":" {action} }
                ["|" "*" ":" {action} ] "]"</verb>
<item><verb>"["	parameterizedChoiceOpId	 "(" valueId ")"
                {"|" valueId {"," valueId} ":" {action} }
                ["|" "*" ":" {action} ]	"]"</verb>
</enum>
<!-- end.sgml -->
</article>

