IV. Reference

Here are reference versions of the documentation for each subsystem, these go very deep into details.

Table of Contents
17. Smtpserver Reference
17.1. Smtpserver Runtime Parameters
17.2. Smtpserver Configuration
17.2.1. Smtpserver configuration; PARAM -entries
17.3. policy-builder.sh utility
17.4. Relaying Control Policy Language
17.4.1. Semantics
17.5. Content Based Filtering
18. Sendmail Reference
19. Rmail Reference
20. zmailer(3) Reference
21. Router Reference
21.1. ZMSH Script Language
21.1.1. ZMSH Usage:
21.1.2. ZMSH Parameters:
21.1.3. ZMSH Debug options:
21.2. Configuration Script Writing Rules
21.3. Script Security Issues
21.4. Router Script Well Known Entrypoints
21.4.1. The process() function
21.4.2. The router() function
21.4.3. The crossbar() function
21.4.4. The server() function
21.5. Script Language Internal Functions
21.5.1. ":" (doublecolon)
21.5.2. ".", "include"
21.5.3. "[", "test"
21.5.4. attributes
21.5.5. basename
21.5.6. break
21.5.7. builtin
21.5.8. car
21.5.9. cat
21.5.10. cd
21.5.11. cdr
21.5.12. channel
21.5.13. continue
21.5.14. daemon
21.5.15. db
21.5.16. dblookup
21.5.17. echo
21.5.18. elements
21.5.19. envars
21.5.20. erraddron
21.5.21. eval
21.5.22. exit
21.5.23. export
21.5.24. filepriv
21.5.25. first
21.5.26. gensym
21.5.27. get
21.5.28. getopts
21.5.29. grind
21.5.30. groupmembers
21.5.31. hash
21.5.32. homedirectory
21.5.33. host
21.5.34. hostname
21.5.35. ifssplit
21.5.36. lappend
21.5.37. last
21.5.38. length
21.5.39. list
21.5.40. listaddresses
21.5.41. listexpand
21.5.42. login2uid
21.5.43. lreplace
21.5.44. malcontents
21.5.45. printaliases
21.5.46. process
21.5.47. read
21.5.48. recase
21.5.49. recipient
21.5.50. relation
21.5.51. rest
21.5.52. return
21.5.53. returns
21.5.54. rfc822
21.5.55. rfc822date
21.5.56. rfc822syntax
21.5.57. runas
21.5.58. sender
21.5.59. set
21.5.60. shift
21.5.61. sleep
21.5.62. squirrel
21.5.63. stability
21.5.64. "test", "["
21.5.65. times
21.5.66. trace
21.5.67. trap
21.5.68. type
21.5.69. uid2login
21.5.70. umask
21.5.71. unset
21.5.72. untrace
21.5.73. user
21.5.74. wait
22. Scheduler Reference
22.1. Configuration Language
22.1.1. PARAM-entries
22.1.2. Group-Clause selection
22.1.3. Clause components
22.1.4. Variables and keywords
22.2. Resource Management
22.3. scheduler.auth file
22.4. mailq protocol v.1
22.5. mailq protocol v.2
22.6. Transport Agent Interface Protocol
22.7. Canned (Error) Message Files
22.8. Security Issues
23. Transport Agents References
23.1. mailbox
23.2. hold
23.3. smtp
23.4. sm - zmailer Sendmail compatible transport agent
23.4.1. configuration of sm
23.5. expirer
23.6. libta - Transport Agent Support Library
23.6.1. Function groupings
23.6.2. Function listings
23.6.3. Function usage examples
23.7. Security Issues
24. ZMailer Utilities Reference
24.1. zmailer command script
24.1.1. zmailer bootclean
24.1.2. zmailer start
24.1.3. zmailer stop, zmailer kill
24.1.4. zmailer nuke
24.1.5. zmailer router
24.1.6. zmailer scheduler
24.1.7. zmailer smtp(server)
24.1.8. zmailer newdb
24.1.9. zmailer newal(iases)
24.1.10. zmailer newf(qdnaliases)
24.1.11. zmailer new-route(s)
24.1.12. zmailer new-local(names)
24.1.13. zmailer logsync
24.1.14. zmailer logrotate
24.1.15. zmailer resubmit
24.1.16. zmailer cleanup
24.1.17. zmailer freeze
24.1.18. zmailer thaw, zmailer unfr(eeze)
24.2. The newdbprocessor script
24.3. The newdb script
24.4. The makedb utility
24.5. The dblook utility
24.6. The policy-builder.sh script
24.7. autoanswer
24.8. vacation

Chapter 17. Smtpserver Reference

The ZMailer distribution contains an smtpserver program for the BSD socket implementation of TCP/IP. It is an asynchronous implementation, in that while address syntax is checked in real time, semantics are not, nor are other (optional in the SMTP standard) functions that require router functionality.

The server will run an RFC-821 syntax scanner for addresses, plus possible policy analysis phase, and if things are ok, it says Yes yes, sure! to everything. The program may also be used in non-daemon mode to unpack BSMTP format messages on the standard input stream.

This program implements the server side of the SMTP protocol as described in RFC821, and knows about the common extensions to the protocol expected by sendmail and BSMTP clients. By default the program will kill the previous smtpserver daemon, if any, then detach and listen for SMTP connections. Incoming messages will be submitted for processing using the zmailer(3) interface to ZMailer. Some non-trivial address checking is doable in optional policy analysis functions within the smtpserver, or can be acomplished with synchronous (or asynchronous) running of router. This behaviour can be changed by a command line option (or HELO/EHLO style patterns) if you cannot afford to transfer data just to bounce it back.

All router assisted checking is done by executing the router(8) program in interactive mode, and executing well-known shell function with well-known parameters for each request.

The server implements also most of the ESMTP facilities invented up to date (Feb, 2000). The ones that are active are visible at greeting response to EHLO command, as can be seen in figure Figure 17-1.

Figure 17-1. Sample EHLO greeting with smtpserver

$ telnet 127.1 smtp
Connected to 127.1.
Escape character is '^]'.
220 localhost ZMailer ....
EHLO foo
250-localhost expected "EHLO localhost"
250-SIZE 1234567
250-8BITMIME
250-PIPELINING
250-CHUNKING
250-ENHANCEDSTATUSCODES
250-EXPN
250-VRFY
250-DSN
250-X-RCPTLIMIT 10000
250-ETRN
250 HELP
...

17.1. Smtpserver Runtime Parameters

Usage:

smtpserver [-46aginvBV] [-p port] [-l logfile] [-s 'strict'] [-s [ftveRS]] [-L maxloadaver] [-M SMTPmaxsize] [-P postoffice] [-R router] [-C cfgfile]



Parameters:
-4

Explicitly use IPv4 type of socket even on machines that are capable to do IPv6 type of sockets.

-6

Explicitely (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.

-8

This option is part of optional inbound translate processing; see -X option below.

-a

Turn on RFC931/RFC1413 identification protocol, and log the information acquired with it into the submitted file. Reliability, validity, worthwhileness, ... all such are suspect at this.

-B

Flags the email to arrive via BSMTP channel (via BITNET, for example).

-B cfgfile

Specifies nonstandard configuration file location; the default is $MAILSHARE/smtpserver.conf.

-d nnnn

This option sets numeric debug value. Any non-zero will work. This numeric argument is provision for possible bit-flag or level oriented debugging mode….)

-g

The gullible option will make the program believe any information it is told (such as origin of a connection) without checking.

-h

Check HELO parameter very closely (syntax), and if it is bad, complain with “501”. Such behaviour is against interoperability minded Be lenient on what you accept policy, and apparently will break a lot of common clients….

-i

Runs the server interactively, which makes it usable for processing a batched SMTP stream (BSMTP) on stdin. With -v option this echoes incoming BSMTP to create more accurate faximile of BITNET BSMTP mailers.

-L maxloadaver

The maximum load-average the system is under when we still accept email.

Not all systems are supported for load-aver extraction; and as that information happens to be very poorly extractable without major magics, it is our considered opinnion that it is better to spend time to figure other methods for limiting incoming email induced load impact, than trying to see any load-average — anyway the ZMailer smtpserverused without interactive routing is very low load inpact system.

-l 'SYSLOG'

Specifies that incoming SMTP conversations are logged via syslog(3) to system syslogd(8) server by using facility LOG_MAIL and level LOG_DEBUG messages.

-l LOGFILE

Specifies a logfile and enables recording of incoming SMTP conversations to go there.

This can be used in parallel with -l 'SYSLOG' version!

-M SMTPmaxsize

Defines the absolute maximum size we accept from incoming email. (Default: infinite) (This is a local policy issue.)

-n

Indicates the program is being run from {\em inetd(8)}.

-P postofficedir

Specifies an alternate $POSTOFFICE/ directory.

-P port

Specifies the TCP port to listen on instead of the default SMTP port: 25.

-R routerpath

Specifies an alternate router(8) program to use for address verification.

-s 'strict'

This turns server protocol processing into extremely strict mode, any misplaced character is rejected. Not very practical in real file, but nice for protocol interoperability bakeout testing.

-s 'strict'

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:

f

Run MAIL FROM address through online router for analysis.

t

Run RCPT TO address through online router for analysis.

v

Enable VRFY command for this style selector (if configuration PARAM vrfycmd is in effect)

e

Enable EXPN command for this style selector (if configuration PARAM expncmd is in effect)

R

Require incoming addresses to be of fully-qualified domained form.

Don't use this if you want to allow non-domained addresses accepted into your server through SMTP.

S

Allow Sloppy behaviour from the sending smtp clients; namely allow MAIL FROM:foo@bar, that is, an addresses without mandatory (RFC-821) angle braces.

The flags are concatenated to form the argument to the -s option. The default is ve.

-S suffixstyle

This defines log suffix which can alter the default logfile name to one which splits incoming traffic into separate files.

Possible values are:

'remote'

Append remote hostname to the logfile name (after a dot) so that from host “foo.bar.edu” the logfile would be: “smtpserver.foo.bar.edu”.

'local'

Append local end reversed hostname to the logfile name (after a dot) so that in multihomed hosts all different “hosts” have different logfiles. Such does, of course, assume that different IP addresses in the host reverse to different names.



-v

This is a verbose option to be used with -i option. This is especially for “BSMTP” processing.

-V

prints a version message and exits.

-X

This is Xlate option. For more info, see source file:

 

“It may be necessary in some cases (e.g. in Cyrillic-language countries) to translate charset on the messages coming from the clients with, e.g. old Eudora or other MUAs that do not correctly support koi8-r charset.  …”

 
--README.translation  


17.2. Smtpserver Configuration

If the $MAILSHARE/smtpserver.conf file exists it is read to configure two kinds of things. Specifically the following:

PARAM -entries

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

  • system parameters

  • help texts

  • acceptance/rejection database definitions



The style (-s) options

Behaviour is based on glob patterns matching the HELO/EHLO name given by a remote client. Lines beginning with a “#” 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.



17.2.1. Smtpserver configuration; PARAM -entries

PARAM maxsize nn

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

This sets system default value, and overrides commandline -M option.

PARAM max-error-recipients nn

In case the message envelope is an error envelope (MAIL FROM:<>), 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… Of course as spam-spewers learn, they begin just sending single recipients per message — less efficient, but working still…)

PARAM MaxSameIpSource nn

(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 either — 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 huge 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.

PARAM TcpRcvBufferSize nn

This sets setsockopt(SO_RCVBUF) value, in case the system default is not suitable for some reason.

PARAM TcpXmitBufferSize nn

This sets setsockopt(SO_SNDBUF) value, in case the system default is not suitable for some reason.

PARAM ListenQueueSize nn

This relates to newer systems where the listen(2) 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 the socket stops answering to incoming SYN packets requesting opening of a connection. Such sockets have not opened sufficiently to reach a state where bi-directional communication has been established, thus they won't appear to accept(2) yet for the server to pick them up!

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.

Most modern 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.

Do consult your system specific information on how much memory each nascent (and matured) socket will require before you commence upping this very much. You might commit heaps of unswappable memory to useless waste.

PARAM help string

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.

PARAM debugcmd

Enables DEBUG command in the server. This command turns on various trace functions which ruin the protocol from standards compliant client, but may help interactive debuggers.

PARAM expncmd

Enables EXPN command in the server.

PARAM vrfycmd

Enables VRFY command in the server.

PARAM PolicyDB dbtype dbpath

This defines the database type, and file path prefix to the binary database containing policy processing information. 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.)

More information below, and at newdb at Section 24.3

PARAM allowsourceroute

When present, this parameter will not convert input of form <@aa,@bb:cc@dd> into source-route-less form of <cc@dd> Instead it carries the original source-route into the system as is.

A possible smtpserver configuration file is shown in figure Figure 17-2.

Figure 17-2. Full-featured smtpserver.conf file example

#
# {\rm{}smtpserver.conf - autogenerated edition}
#
#PARAM maxsize              10000000    # {\rm{}Same as -M -option}
#PARAM max-error-recipients        3    # {\rm{}More than this is propably SPAM!}
#PARAM MaxSameIpSource            10    # {\rm{}Max simultaneous connections from}
#                                       # {\rm{}any IP source address}
#PARAM TcpRcvBufferSize        32000    # {\rm{}Should not need to set!}
#PARAM TcpXmitBufferSize       32000    # {\rm{}Should not need to set!}
#PARAM ListenQueueSize            10    # {\rm{}listen(2) parameter}

# {\rm{}Enables of some commands:}
PARAM debugcmd
PARAM expncmd
PARAM vrfycmd

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 =============================================================

# {\rm{}Uncomment following for not to strip incoming addresses of format:}
# <@aa,@bb:cc@dd>  into non-source-routed base form: <cc@dd>
#PARAM  allowsourceroute

PARAM   accept-percent-kludge # "localpart" can contain '%' and '!'
#PARAM  reject-percent-kludge # "localpart" can't contain  --"--

# {\rm{}The policy database:  (NOTE: See  'makedb'  for its default suffixes!)}
PARAM  policydb   btree  /opt/mail/db/smtp-policy

#
# HELO/EHLO-pattern     style-flags
#               [max loadavg]

localhost           999 ftveR
some.host.domain    999 !NO EMAIL ACCEPTED FROM YOUR MACHINE

# {\rm{}If the host presents itself as:  HELO [1.2.3.4], be lenient to it..}
# {\rm{}The syntax below is due to these patterns being SH-GLOB patterns,}
# {\rm{}where brackets are special characters.}

\[*\]               999 ve

# {\rm{}Per default demant strict syntactic adherence, including fully}
# {\rm{}qualified addresses for  MAIL FROM, and RCPT TO.  To be lenient}
# {\rm{}on that detail, remove the "R" from "veR" string below:}

*                   999 veR

17.3. policy-builder.sh utility

The policy database that {\em smtpserver} uses is built with {\tt policy-builder.sh} script, which bundles together a set of policy source files:

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


At the moment, {\tt smtp-policy.spam} source is retrieved with LYNX from
the URL:
\begin{alltt}\medskip\scriptsize\medskip
http://www.webeasy.com:8080/spam/spam_download_table
\medskip\end{alltt}\medskip
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.

{\em If you want, you can modify your {\tt smtp-policy.src} boilerplate
file as well as your installed {\tt\small policy-builder.sh} script.}
{\bf In fact you SHOULD modify both to match your environment!}

Doing {\tt make install} will overwrite {\tt\small policy-builder.sh},
but not {\tt smtp-policy.src}.

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

\begin{description}
\item[\tt localnames] \mbox{}

Who we are -- ok domains for receiving.

\item[\tt smtp-policy.relay] \mbox{}

Who can use us as outbound relay.

Use  {\em\verb/[/ip.number\verb/]//maskwidth}  here for
listing those senders (networks) we absolutely trust.
You may also use domains, or domain suffixes so that the IP-reversed
hostnames are accepted (but that is a it risky thing due to ease of
fakeing the reversed domain names):

\begin{alltt}\medskip\hrule\medskip
[11.22.33.00]/24
ip-reversed.host.name
.domain.suffix
\medskip\hrule\end{alltt}\medskip

Server sets its internal “always_accept” flag at the source IP tests
before it decides on what to tell to the contacting client.
The flag is not modified afterwards during the session.

Usage of domain names here is discouraged as there is no way to tell
that domain “foo.bar” here has different meaning than same domain
elsewere -- at “{\tt smtp-policy.mx}”, for example.

\item[\tt smtp-policy.mx] \mbox{}

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
“acceptifmx -” attribute at the generic boilerplate.
List here domain names. 
\begin{alltt}\medskip\hrule\medskip
 mx-target.dom
 .mx-target.dom
\medskip\hrule\end{alltt}\medskip

You CAN also list here all POSTMASTER addresses you accept email routed to: 

\begin{alltt}\medskip\hrule\medskip
 postmaster@local.domain
 postmaster@client.domain
\medskip\hrule\end{alltt}\medskip

these are magic addresses that email is accepted to, even when everything
else is blocked. 

\item[\tt smtp-policy.spam] \mbox{}

Those users, and domains that are absolutely no-no for senders,
or recipients no matter what earlier analysis has shown.
(Except for those senders that we absolutely trust..)

\begin{alltt}\medskip\hrule\medskip
 user@domain
 user@
 domain
\medskip\hrule\end{alltt}\medskip

The “{\tt policy-builder.sh}” builds this file from external sources. 

\end{description}

17.4. Relaying Control Policy Language

Policy based filter database boilerplate for smtp-server.

File:  {\tt \$MAILVAR/db/smtp-policy.src}

This file is compiled into an actual database using the command:
\begin{alltt}\medskip\hrule\medskip
  \$MAILBIN/policy-builder.sh
\medskip\hrule
\end{alltt}\par


The basic syntax of non-comment lines in the policy source is:
\begin{alltt}\medskip\hrule\medskip
  key  [attribute value]* [= _tag]
\medskip\hrule
\end{alltt}\par

There are any number of attribute-value pairs associated with the key.

There can be only one key of any kind currently active, unless “{\em makedb}”
is called with “-A” option (Append mode) in which case latter appearances
of some keys will yield catenation of of latter data into previous datasets.
(This may or may not be a good idea…)

The key can be any of following forms:
\begin{description}
\item[\rm domain, or .domain.suffix] \mbox{} \\
a domain name optionally preceded by a dot (.)

\item[\rm“user@”, or “user@domain”] \mbox{} \\
Usernames -- domainless (“user@”) or domainfull.

\item[\rm An IP address in {[}nn.nn.nn.nn{]}/prefix form] \mbox{} \\
Unspecified bits must be 0.
(Network IPv6 addresses containing IPv4-mapped addresses are translated
 into plain IPv4.)

\item[\rm A tag -- word begining with underscore] \mbox{} \\
An “alias” dataset entry for “=” “attribute” uses.
\end{description}


{\em attribute} and {\em value} are tokens.
They are used by {\tt policytest()} to make decisions.

The attribute scanners operate in a manner, where the first
instance of interesting attribute is the one that is used.
Thus you can construct setups which set some attribute, and
then {\em ignore} all latter instances of that same attribute
which have been pulled in via “{\em = _alias_tag}” mechanism,
for example.

In following, “understood” value is one or both of literals: “+”, “-”,
if they are listed at the definition entry.
In case only one is understood, the other one can be considered as
placeholder which stops the scanner for that attribute.

Attribute names, and understood value tokens are:

\begin{description}
\item[\tt = _any_tag] \mbox{} \\
The analysis function will descend to look up “_any_tag” from
the database, and expand its content in this place.

\item[\tt rejectnet +] \mbox{} \\
Existence of this attribute pair sets persistent session flag:
“always-reject”, which causes all “MAIL FROM” and “RCPT TO”
commands to fail until end of the session.

This is tested for at the connection start against connecting
IP address, and against IP-reversed domain name.
This is also tested against the “HELO/EHLO” supplied parameter
string.

Use of this should be limited only to addresses against which you
really have grudges.

\item[\tt freezenet +] \mbox{} \\
Existence of this attribute pair sets persistent session flag:
“always-freeze”, which will accept messages in, but all of them
are moved into “freezer” spool directory.

This is tested for at the same time as “rejectnet”.

\item[\tt rejectsource +] \mbox{} \\
Existence of this attribute pair rejects “MAIL FROM” address,
and thus all subsequent “RCPT TO” and “DATA” transactions
until new “MAIL FROM” is supplied.

\item[\tt freezesource +] \mbox{} \\
Existence of this attribute pair causes subsequently following
“DATA” phase message to be placed into “freezer” spool directory.

This is tested for only at “MAIL FROM”, and subsequent “MAIL FROM”
may supply another value.

\item[\tt relaycustomer +/-] \mbox{} \\
Existence of this attribute pair is tested for at “MAIL FROM”,
and it affects subsequent “RCPT TO” address testing.

Pair “relaycustomer -” is a placeholder no-op, while
“relaycustomer +” tells to the system that it should not
test the “RCPT TO” address very deeply.

{\em Usage of this attribute is not encouraged!
Anybody could get email relayed through just by claiming
a “MAIL FROM” domain which has this attribute.}

\item[\tt relaycustnet +] \mbox{} \\
Existence of this attribute pair is tested for at the  connection
start against connecting IP address, and against IP-reversed domain name.

If this pair exists, session sets persistent “always-accept” flag,
and will not do further policy analysing for the “MAIL FROM”, nor
“RCPT TO” addresses.  (Except looking for valid A/MX data from the
DNS for the sender/recipient domains.)

\item[\tt fulltrustnet +] \mbox{} \\
Because the DNS lookups still done with “relaycustnet +” setting on,
a massive feed for fanout servers might become slowed down/effectively
killed, unless we use “fulltrustnet +” specification for the feeder
host.  Then everything is taken in happily from that source address.

\item[\tt trustrecipients +] \mbox{} \\
This is a variant of “relaycustnet,” where  “RCPT TO” addresses are
not checked at all, but “MAIL FROM” addresses are looked up from
the DNS. (Unless some other test with the “MAIL FROM” domain name
has matched before that.)

\item[\tt trust-whoson +] \mbox{} \\
If the system has been compiled with support to “{\em whoson}” services,
see file “{\em whoson-*.tar.gz}” in the “contrib/” subdirectory.
This facilitates indirectly authenticated (via POP/IMAP) SMTP message
submission for dialup-type users.

\item[\tt relaytarget +] \mbox{} \\
With this attribute pair the current “RCPT TO” address is accepted in
without further trouble. (Theory being, that keys where this attribute
pair exist are fully qualified, and valid, thus no need for DNS analysis.)

See “RCPT TO” processing algorithm for further details.

\item[\tt relaytarget -] \mbox{} \\
This attribute pair causes instant rejection of the current “RCPT TO”
address.

See “RCPT TO” processing algorithm for further details.

\item[\tt freeze +] \mbox{} \\
When “RCPT TO” address test meets this attribute pair, the entire
message will be placed into “freezer” directory.

\item[\tt acceptifmx +/-] \mbox{} \\
This attribute pair is used to give fuzzy feeling in anti-relay setups
so that we don't need to list {\bf all} those target domains that we
are allowing to use ourselves as relays.

This will basically check that “RCPT TO” address has our server
as one of its MX entries.

The value (“+” or “-”) determines how “severe” the nonexistence
of MX data is.  With “+” the server will yield “400” series temporary
error with implied invitation to try again, and with “-” the server will
yield “500” series permanent error.

\item[\tt acceptifdns +/-] \mbox{} \\
This attribute pair is complementary for the “acceptifmx” in sense
that it accept the recipient address in case the DNS system has any
A or MX information for it.

This attribute pair should not be used.

\item[\tt senderokwithdns +/-] \mbox{} \\
This attribute pair will do DNS analysis for “MAIL FROM” domain, and
accept it only if there exists A or MX data for the said domain.

The value (“+” or “-”) determines how “severe” the nonexistence
of DNS data is.  With “+” the server will yield “400” series temporary
error with implied invitation to try again, and with “-” the server will
yield “500” series permanent error.


\item[\tt sendernorelay +] \mbox{} \\
Tested at “MAIL FROM” address domain, and affects “RCPT TO”
address domain analysis.
{\em At the moment this attribute does not make sense, don't use!}

\item[\tt test-dns-rbl +] \mbox{} \\
This attribute pair will use Paul Vixie's RBL
( HTTP://maps.vix.com/rbl/ )
system to block undesired connection sources.

\item[\tt rply-dns-rbl +] \mbox{} \\
\item[\tt test-rply-dns-rbl +] \mbox{} \\
This is a “recipient selective” version of the RBL.
The first one is to be placed into the default address case
(the “[0.0.0.0]/0”), and then the latter can be used in given
destination domain(s) to test for the result of the lookup.

This allows selective usage of 'RBL' blocking via this server.
For example if you have {\tt smtp-policy.mx} file listing special
cases (opposite of your default domain address “.” values)

\begin{alltt}\medskip\hrule\medskip
 fobar.com  test-rply-dns-rbl + relaytarget +
 barfo.dom  test-rply-dns-rbl + relaytarget +
\medskip\hrule\end{alltt}\medskip

The selectivity can be either by means of listing those where the test
happens, or those where it doesn't happen -- the latter means that
the default domain address (“.”) must have “test-rply-dns-rbl +” entry.

\item[\tt maxinsize nnn] \mbox{} \\
This attribute pair yields numeric limit for incoming message
size.  With this you can define source specific message size
limits so that if your intranetwork has a system with lower
inbound message size, than you do, you can report this limit
at the “EHLO” responses.

Partly this is placeholder for further code with for example
source/target domain specific runtime enforced size limits.

\item[\tt maxoutsize nnn] \mbox{} \\
Placeholder for further code

\item[\tt localdomain *] \mbox{} \\
Placeholder for further code

\item[\tt message "text string in quotes"] \mbox{} \\
Placeholder for further code
\end{description}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%\end{multicols}

17.4.1. Semantics

The {\tt policytest()} function is called by smtp-server to check the client 
host, the sender's and recipients' addresses.
policytest()  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 the input file is not important, as the file is
compiled into binary database for faster lookup.

When searching for an IP address the entry with the most common (leftside)
bits is returned.   So you can have a [0.0.0.0]/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 server() doesn't find the requested attribute
of the object, it will replace object name with `_tag' and restart the search.

{\Large SCRIPT REMOVED; SEE FILE  smtp-policy.src}

17.5. Content Based Filtering

The ZMailer smtpserver can do also message content analysis with an external program at the end of DATA-dot-phase, and BDAT LAST-phase (that is, when the input message is complete, and final acknowledgement is expected by the email sender.)

The program becomes active if PARAM entry “contentfilter” is set:

# External program for received message content analysis:
#PARAM  contentfilter   $MAILBIN/smtp-contentfilter


The interface to the program is simple synchronous half-duplex one, smtpserver writes relative filepath of the message into programs stdin, ending it with a newline. The filter programs reply must begin with a signed integer, then whatever text is desired to give to the user.

The contentfilter program is started without parameters running userid of daemon in directory $POSTOFFICE/.

The program must silently wait for input, which is full path to the message spool file, analyze it, and reply with exactly one line matching rule of: %i — begin with signed integer, then have one or more whitespace, then whatever filter writer liked to tell.

General rule:

 -1 negatives are condemned into rejection
  0 zero is ok! gladly accepted
  1 positives are sent into the freezer


The program may produce also the numeric SMTP reply codes in its response text:

 -1
 -1 250 2.7.1 Glad to see some spam, immediately destroyed :)
  0
  0 250 2.6.0 Message OK!
  1
  1 550 5.7.1 That is spam, rejected!


If the message has no text, some defaults are supplied. If the message text starts with numbers, it is presumed that it contains both the SMTP reply code, and ENHANCEDSTATUSCODE before the text. (If no ENHANCEDSTATUSCODE part is present, then some possibly senseless default is supplied.)

Interface message text lines beginning with anything except signed integer are logged, and the communication channel from the smtpserver to the contentfilter program is closed. Interface continues to scan things reported by the contentfilter program, and if no properly formatted line appears, default is to send the message into the freezer ("-1"); FIXME! FIXME! "-1" == Kill ??? (Copy&paste from man-page, which may have a bug in it..)

Chapter 18. Sendmail Reference

This sendmail program is an emulation of the original sendmail 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 mail, rather it is used by the old User Agent programs, e.g., mail(1), to submit mail. This mechanism has been superseded by the zmailer(3) 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 STDIN 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 userid, except for root 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. (modulo used options.)

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

Usage:
/usr/sbin/sendmail: unknown option -?
Usage: sendmail [sendmail options] [recipient addresses]
 ZMailer's sendmail recognizes and implements following options:
   -B bodytype  -  Valid values: 8BITMIME, 7BIT
   -C conffile  -  specifies config file (meaningfull for -bt)
   -E           -  flag 'external' source
   -F 'full name'  sender's full name string
   -N notifyopt -  Notify option(s): NEVER or a set of:
                                     SUCCESS,DELAY,FAILURE
   -P priority# -  numeric priority for ZMailer router queue
                   pre-selection
   -R returnopt -  Error report return option, either of: FULL, HDRS
   -U           -  Flag as 'user submission'
   -V envidstring - XTEXT encoded ENVID string
   -b?          -  operational mode flags
   -bd          -  starts smtpserver in daemon mode
   -bi          -  runs 'newaliases' command
   -bm          -  deliver mail; always :-)
   -bp          -  runs 'mailq' command
   -bs          -  speak smtp; runs server in interactive mode
   -bt          -  starts router in interactive test mode
   -e*          -  (ignored)
   -f fromaddr  -  sets envelope from address for the message
   -i           -  on inputs from tty this will ignore SMTP-like
                   dot-EOF
   -m           -  send a copy of the message to the sender too
                   (ignored)
   -o*          -  multiple options; those not listed cause error
   -oQ queuedir -  defines POSTOFFICE directory for message
                   submission
   -ob*         -  (ignored)
   -od*         -  (ignored)
   -oe*         -  (ignored)
   -oi          -  alias of '-i' option
   -or*         -  (ignored)
   -p submitprotocol - value for 'with' label at 'Received:' header
   -q*          -  queue processing commands (ignored)
   -r fromaddr  -  (alternate for -f)
   -t           -  scan message rfc822 headers for recipients
   -v           -  verbose trace of processing


Parameters:

-bm

asks sendmail to deliver mail, which it does anyway. This option has no effect.

-bs

will start a SMTP server reading from STDIN. This causes the smtpserver(8) program to be executed.

-bd

starts the router(8) and scheduler(8) programs to emulate sendmail's daemon mode. This is not a recommended method to start these programs, instead use zmailer(1) script.

-bt

runs the router(8) in interactive mode for testing.

-bu

runs newaliases(8) to rebuild the alias file database.

-bp

runs mailq(1) to print the mail transport queue status.

-C configfile

specifies the router(8) configuration file.

-E

indicates the origin of this message is an insecure channel. This should be used when sendmail 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 userid is “trusted”.

-f address

specifies the sender address. This is the default originator address if there is no From: headerin the message. It becomes the Sender: address otherwise. In either case if the current userid is not “trusted” by the mailer, it is free to ignore both this option and any header information to ensure properly authenticated originator information.

-F fullname

specifies the full name of the (local) sender.

-i

tells sendmail to not use a period (“.”) on a line by itself as a message terminator, only the end of file will terminate the message.

-m

asks the mailer not to ignore the originator in the addressee list. This is default behaviour, so this option has no effect.

-N notify

sets Delivery-Status-Notification notify parameter to be: NEVER, or any combination of: SUCCESS, FAILURE, DELAY.

-oi

is like -i.

-oQ postoffice

specifies an alternate $POSTOFFICE/ directory.

-q

asks for queue processing. This option has no effect.

-Q retmode

sets Delivery-Status-Notification parameter to be either of: FULL, HDRS.

-r address

is like -f.

-t

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.

-v

will report the progress of the message after it has been submitted. The sendmail process will write verbose log information to the STDERR stream until the scheduler deletes the message.

-V envid

sets Delivery-Status-Notification parameter ENVID to be any arbitrary [xtext] string.



Chapter 19. Rmail Reference

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

uux - -r -asender -gC thishost!rmail (recipient1) (recipient2) ...

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

rmail recipient1 recipient2 ...


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

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

The expected input format looks like:

  From address3  date3 remote from host3
  >From address2  date2 remote from host2
  >From address1  date1 remote from host1
followed by the rest of the message. This is considered equivalent to the following (as it might appear in a mailbox):
  From host3!host2!host1!address1 date
  Received: by host3 ... ; date3
  Received: by host2 ... ; date2
  Received: by host1 ... ; date1


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

Usage:

rmail [-d] [-h somewhere] recipient...



Parameters:
-d

turns on debugging output.

-h somewhere

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

Chapter 20. zmailer(3) Reference

Usage:
#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();

At linkage time use -lzmailer.

mail_open() will return a FILE * to a message file that should be written to by the application. This message file contains three parts:

  • the message envelope

  • the message header

  • the message body

The exact format of these components depend on the message protocol, which must be specified as the parameter to mail_open(). The choices are predetermined by the capabilities of the mailer, and are defined in the header file. The known possibilities are:
MSG_RFC822

this is the only format supported by default by the mailer. The message headers and body in this format are defined by the IETF Request For Comments 822 and 1123. The message envelope syntax is similar to the message header syntax.

MSG_FAX

intended for fax transmissions. (never used)

MSG_UUCP

intended for old style UUCP format message headers (never used)

MSG_X400

intended for X.400(88) messages.



The mail_open() routine will look for $FULLNAME and $PRETTYLOGIN 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 mail_open() routine corresponds to the return value of an fopen(3), and similarly the return values from mail_abort() and mail_close() correspond to the return value of fclose(3).

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

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

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

Similarly the mail_host() 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.

Envelope header lines:

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

 *external \n
 *rcvdfrom %s@%s (%s) \n
 *bodytype %s \n
 *with %s \n
 *identinfo %s \n

Either:
  from <%s> \n
Or:
  channel error \n

 *envid %s \n
 *notaryret %s \n

Then for each recipient pairs of:

 *todsn [NOTIFY=...] [ORCPT=...] \n
 to <%s> \n

Just before the data starts, a magic entry:

 env-end \n


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

Example:

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


Environment variables:

FULLNAME

variable defines textual fullname, for example: “Sample User”

PRETTYLOGIN

variable defines user@node format of what user wants to claim as his/her own address (it must match those of mail router accepts.)



Z-environment variables:

POSTOFFICE

defines the directory where all $POSTOFFICE/ functions are. Example:

  POSTOFFICE=/var/spool/postoffice/


ROUTERDIRS

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:

  ROUTERDIRS=router1:router2:router3:router4




Chapter 21. Router Reference

Table of Contents
21.1. ZMSH Script Language
21.1.1. ZMSH Usage:
21.1.2. ZMSH Parameters:
21.1.3. ZMSH Debug options:
21.2. Configuration Script Writing Rules
21.3. Script Security Issues
21.4. Router Script Well Known Entrypoints
21.4.1. The process() function
21.4.2. The router() function
21.4.3. The crossbar() function
21.4.4. The server() function
21.5. Script Language Internal Functions
21.5.1. ":" (doublecolon)
21.5.2. ".", "include"
21.5.3. "[", "test"
21.5.4. attributes
21.5.5. basename
21.5.6. break
21.5.7. builtin
21.5.8. car
21.5.9. cat
21.5.10. cd
21.5.11. cdr
21.5.12. channel
21.5.13. continue
21.5.14. daemon
21.5.15. db
21.5.16. dblookup
21.5.17. echo
21.5.18. elements
21.5.19. envars
21.5.20. erraddron
21.5.21. eval
21.5.22. exit
21.5.23. export
21.5.24. filepriv
21.5.25. first
21.5.26. gensym
21.5.27. get
21.5.28. getopts
21.5.29. grind
21.5.30. groupmembers
21.5.31. hash
21.5.32. homedirectory
21.5.33. host
21.5.34. hostname
21.5.35. ifssplit
21.5.36. lappend
21.5.37. last
21.5.38. length
21.5.39. list
21.5.40. listaddresses
21.5.41. listexpand
21.5.42. login2uid
21.5.43. lreplace
21.5.44. malcontents
21.5.45. printaliases
21.5.46. process
21.5.47. read
21.5.48. recase
21.5.49. recipient
21.5.50. relation
21.5.51. rest
21.5.52. return
21.5.53. returns
21.5.54. rfc822
21.5.55. rfc822date
21.5.56. rfc822syntax
21.5.57. runas
21.5.58. sender
21.5.59. set
21.5.60. shift
21.5.61. sleep
21.5.62. squirrel
21.5.63. stability
21.5.64. "test", "["
21.5.65. times
21.5.66. trace
21.5.67. trap
21.5.68. type
21.5.69. uid2login
21.5.70. umask
21.5.71. unset
21.5.72. untrace
21.5.73. user
21.5.74. wait

The router daemon makes all decisions affecting the processing of messages in ZMailer.

A mail message is submitted by placing it in a file in the $POSTOFFICE/router/ directory. The router 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 $POSTOFFICE/scheduler/ and $POSTOFFICE/transport/ directories for use by the scheduler in the next step of message processing. The original message file is then moved to the $POSTOFFICE/queue/ directory.

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

Usage:

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 zmailer(1) script, as in "zmailer router". This will start the router as a daemon and kill the previous incarnation of the router.

router [-diksSV] [-f configfile] [-n #routers] [-o zmsh-options] [-t traceflag] [-L logfile] [-P postoffice]



Parameters:

-d

Detach and run as a daemon.

-f configfile

Overrides the default configuration file $MAILSHARE/router.cf.

-i

Run interactively, presenting a zmsh session with the configuration file preloaded.

-k

Kill the currently running router by sending it a SIGTERM signal.

-L logfile

Overrides the default log file location $LOGDIR/router.

-n #routers

Starts the specified number of parallel router processes. The default is a single router process.

-o zmsh-options

Sets the option string passed on the internal zmsh invocation. The default is -O. Note that the leading "-" is mandatory. See zmsh(1) (at Section 21.1.2) for the available options.

-P postoffice

Specifies an alternate $POSTOFFICE/ directory.

-S

Can be used to turn off non-serious syslogging.

-s

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.

-t traceflag

Sets trace options, one per -t switch, even before the configuration file is loaded. This is otherwise equivalent to the builtin trace command. The currently known options are: assign, bind, compare, db, final, functions, matched, memory, on, regexp, resolv, rewrite, router, and sequencer.

-V

Print version message and run interactively.



To restart a router daemon:

   router -dk


To test an address, start up an interactive session:

  router -i
or if the ZMailer sendmail(8) is installed:
  sendmail -bt


Then just use the pre-defined functions.

21.1. ZMSH Script Language

zmsh is an implementation of the Bourne shell suitable for use with the ZMailer router(8) 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 in-core for future reference. If the input is an included file, the shell will try to save the byte-code form in a .fc file associated with the input file. For example, if input is from file.cf, the shell will try to create fc/file.fc and then file.fc. These files will in turn be searched for and loaded (after a consistency check) whenever a .cf file is included.

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

21.1.1. ZMSH Usage:

zmsh [-CILOPRSYaefhinstuvx] [-c command] [script ...]



21.1.2. ZMSH Parameters:

-c command

Run the given argument as a shell command script.

-a

Automatically export new or changed shell variables.

-e

Exit on non-zero status return of any command.

-f

Disables filename generation.

-h

Hash and cache the location of Unix commands. The option is set by default.

-i

This shell is interactive, meaning prompts are printed when ready for more input, SIGTERM signal is ignored, and the shell does not exit easily. This flag is automatically set if stdin and stderr are both attached to a /dev/tty.

-n

Read commands but do not execute them.

-s

Read commands from stdin. If there are non-option arguments to the shell, the first of these will be interpreted as a shell script to open on stdin, and the rest as arguments to the script.

-t

Exit after running one command.

-u

Unset variables produce an error on substitution.

-v

Print shell input as it is read.

-x

Print commands as they are executed.



21.1.3. ZMSH Debug options:

-C

Print code generation output onto stdout. If this option is doubled, the non-optimized code is printed out instead.

-I

Print runtime interpreter activity onto /dev/tty.

-L

Print lexer output onto stdout.

-O

Optimize the compiled script. If this option is doubled, the optimized code is also printed out.

-P

Print parser output (S/SL trace output) onto stdout.

-R

Print I/O actions onto /dev/tty.

-S

Print scanner output (token assembly) onto stdout.

-Y

Open /dev/tty for internal debugging use.



21.2. Configuration Script Writing Rules

Text to be inserted here.

21.3. Script Security Issues

Text to be inserted here.

21.4. Router Script Well Known Entrypoints

This section describes the router internal functions used as entrypoints by various uses inside and outside the router program.

21.5. Script Language Internal Functions

This section describes the router internal functions.

FIXME! FIXME! some internal functions are missing from this listing!

21.5.1. ":" (doublecolon)

Syntax:

: <SPC> anything else forming a command pipeline



Description:

none

Return Values:

0

Options:

none

Notes:

none

21.5.2. ".", "include"

Syntax:

. scriptfilename



Alternate syntax:

include scriptfilename



Return Values:

Exit status of script evaluation, or specifically:

1

File not found, or not fstat:able.

2

Internal loadeval() didn't yield same result as fstat:ed file size is.

64

Usage: Not exactly one parameter, or it is a void string.



Options:

none

Notes:

This puts the running script to read more script from given filename.

21.5.3. "[", "test"

Syntax:

[ test parameters ]



Alternate syntax:

test test parameters



Return Values:

1

True.

0

False.

-1

Error.



Options:

  • File testing unary prefix functions:

    -b file

    True if file exists and is block special.

    -c file

    True if file exists and is character special.

    -d file

    True if file exists and is a directory.

    -f file

    True if file exists and is a regular file.

    -g file

    True if file exists and is set-group-id.

    -k file

    True if file has its "sticky" bit set.

    -p file

    True if file exists and is a named pipe.

    -r file

    True if file exists and is readable.

    -s file

    True if file exists and has a size greater than zero.

    -t [fd]

    True if fd is opened on a terminal. If fd is omitted, it defaults to 1 (standard output).

    -u file

    True if file exists and its set-user-id bit is set.

    -w file

    True if file exists and is writable.

    -x file

    True if file exists and is executable.



  • String testing binary functions:

    str1 = str2

    True if the strings are equal.

    The "str1" must not begin with a hyphen "-" character! (Actually they must not be any of the magic prefix-, or infix keyword operators, nor "(", "!", or ")". )

    Suggested test setup:

      [ "x$varname" = "xliteral" ] ...
    


    str1 != str2

    True if the strings are not equal.

    The "str1" must not begin with a hyphen "-" character! (Actually they must not be any of the magic prefix-, or infix keyword operators, nor "(", "!", or ")". )

    Suggested test setup:

      [ "x$varname" != "xliteral" ] ...
    




  • Integer value testing binary functions:

    iexpr -eq iexpr

    True if integer values are equal.

    The iexpr intermediate products are strings for the purposes of this scanners input, but then they are internally treated as system local "integer" datatype.

    The second iexpr can be a pair of: "-l string-expr" which is evaluated as length of that string-expr.

    iexpr -ne iexpr

    True if integer values are not equal.

    The second iexpr can be a pair of: "-l string-expr" which is evaluated as length of that string-expr.

    iexpr -gt iexpr

    True if integer value1 is greater than integer value2.

    The second iexpr can be a pair of: "-l string-expr" which is evaluated as length of that string-expr.

    iexpr -ge iexpr

    True if integer value1 is greater or equal than integer value2.

    The second iexpr can be a pair of: "-l string-expr" which is evaluated as length of that string-expr.

    iexpr -lt iexpr

    True if integer value1 is less than integer value2.

    The second iexpr can be a pair of: "-l string-expr" which is evaluated as length of that string-expr.

    iexpr -le iexpr

    True if integer value1 is less or equal than integer value2.

    The second iexpr can be a pair of: "-l string-expr" which is evaluated as length of that string-expr.



  • File comparison binary functions:

    file1 -nt file2

    True if file1's mtime is newer than file2's.

    Filenames are best to be either absolute paths (begins with "/"), or dot-relative (begins with "./" pair). Unqualified names are hazardous, e.g. "-file-name-".

    file1 -ot file2

    True if file1's mtime is older than file2's. (See comment above.)

    file1 -ef file2

    True if both files have same inode, and device. (See comment above.)



  • Logical functions:

    ! expr

    Unary NOT

    expr -a expr

    Binary AND

    expr -o expr

    Binary OR

    ( expr )

    Parenthesis





Notes:

This is basically the shell "[" a.k.a. "test" program.

Do note that unlike more usual bourne-shells, this does not short-circuit logical evaluations, e.g. falseness of the left side of an AND does not eliminate evaluation of the right side!

Usual "test" precautions with things like parameter data prefixing with some character so that it will not become treated as one of the control options.

Not:
  [ "$(funcname ...)" ]
  [ "$varname" = "value" ]

Ok:
  [ "z$(funcname ...)" ]
  [ "z$varname" = "zvalue" ]


21.5.4. attributes

Syntax:

attributes object-reference



Return Values:

The property list symbol (4th) component of an address quad.

Options:

none

Notes:

none

21.5.5. basename

Syntax:

basename pathname [suffix]



Return Values:

0

ok, result string to stdout.

1

Error.



Options:

If a suffix is given and matches the filename, the suffix too is stripped from the filename.

There are no "-"-type options.

Notes:

Prints the base filename of the pathname.

21.5.6. break

Syntax:

while ...
do
   ...
   break
   ...
done

case ...
   ...
   break
   ...
esac


Return Values:

1



Options:

none

Notes:

none

21.5.7. builtin

Syntax:

NOT IMPLEMENTED!

builtin {builtin command name, and its params}



Return Values:

0



Options:

none

Notes:

NOT IMPLEMENTED!

Ensures that named command is builtin within the scheduler, and not a) external, b) script based.

21.5.8. car

Syntax:

car object-reference



Return Values:

Pointer to copied lisp-object of object-reference's car operation.

Options:

none

Notes:

This command is synonymous to the channel (at Section 21.5.12), and first (at Section 21.5.25) functions.

This version name is for die-hard LISP fans ;-)

21.5.9. cat

Syntax:

cat filenames...



Return Values:

Output into stdout, which can be piped ZMailer router script internally to next receiver in a pipeline.

Options:

none

Notes:

The filenames to be "cat:ed" together need to be regular files.

21.5.10. cd

Syntax:

cd [directory]



Return Values:

0

cd successful.

1

Error, can't find $HOME environment variable.

1

Error, internal chdir(2) call failed. The stderr gets an error string.

64

Bad parameters (too many). (Usage.)



Options:

none

Notes:

none

21.5.11. cdr

Syntax:

cdr object-reference



Return Values:

Pointer to copied lisp-object of object-reference's cdr operation.

Options:

none

Notes:

This command is synonymous to the rest function (at Section 21.5.51).

This version name is for die-hard LISP fans ;-)

21.5.12. channel

Syntax:

channel object-reference



Return Values:

The channel (1st) component of an address quad.

Options:

none

Notes:

The car (at Section 21.5.8), and first (at Section 21.5.25) functions are synonymous to this one.

21.5.13. continue

Syntax:

continue



Return Values:

1



Options:

none

Notes:

This affects control flow by returning it into beginning of enclosing loop construction.

Usage examples:

  while ...
  do
     if ... something ...
     then
       ... something too ...
       continue
     fi
     ... more something ...
  done


21.5.14. daemon

Syntax:

daemon



Return Values:

0



Options:

none

Notes:

Starts the router running in daemon mode, scanning the $POSTOFFICE/router/ directory every few seconds for message files to process. This function is invoked automatically by other code in the router program and has no other purpose.

21.5.15. db

Syntax:

db add database key value
db flush database
db owner database
db print database
db remove database key
db count database
db toc



Return Values:

0

1

Error.



Options:

a[dd]

Add a key,value entry to the database, if possible.

f[lush]

For "incore" database this means deletion of the content, but for others this is IO buffer flush (in case of modifications.)

o[wner]

Print the account name of the owner of the database, if possible. This is usually determined by the files associated with the database.

p[rint]

Print all entries of the database, if possible.

c[ount]

Iterate thru the database and count entries in there.

r[emove]

Remove a key entry from the database, if possible.

t[oc]

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 cache size

  • flags

  • and associated files

See the relation function for more information. (Section 21.5.50)



Notes:

DB type add flush owner print remove count
incore yes yes yes yes yes yes
header yes yes yes yes yes yes
ordered no yes yes yes no yes
unordered yes yes yes yes yes yes
hostsfile no no no yes no no
bind no no no no no no
ndbm yes yes yes yes yes yes
gdbm yes yes yes yes yes yes
dbm yes yes yes yes yes yes
yp (NIS) no no yes yes yes no
bhash yes yes yes yes yes yes
btree yes yes yes yes yes yes
ldap no no yes no no no
selfmatch no no no yes no yes


21.5.16. dblookup

Syntax:

Does lookup via relation defined dblookup vector:

dblookup key [ [ -: defaultkey] -- %subst1 %subst2 ... %subst9 ]

dblookup key [ [ -: defaultkey] -- %subst2 %subst2 ... %subst9 ]

The latter form is for databases which have any driver routine in use!

Return Values:

cell

Lookup result

NULL

Lookup failed, variable $defer may be set if the reason is considered temporary and thus solvable latter.



Options:

The '-:' does supply the "final case" lookup key in cases where various domain shortening lookups reach their end (and have the builtin ultimate default lookup of ".").

  relation -lm%:t $DBTYPE -f $MAILVAR/db/routes$DBEXT routesdb
   ...
  a=$(routesdb $lookupkey -: .:ERROR -- $subst1 $subst2)


With those things the "routes" database can now contain data like:

  .:ERROR  smtp!
  cust.1   smtp!%0
  cust.2   smtp!%0!%1


With "subst*" values below, results would be:

  subst1="foo1"
  subst2="foo2"

  smtp!
  smtp!foo1
  smtp!foo1!foo2
respectively.

Note: The %subst things are used only if the relation definition has -% option flag set!

Notes:

The access function to the database facilities in the router.

FIXME! Notes about %[0-9] substitution rules, and their controls. (That is: relation's -% option! Section 21.5.50)

A complete example of "-:" usage from p-routes.cf:

routes_neighbour (domain, address, A) {
    local tmp

    # We have Alternate default-lookup for cases of locally generated
    # ERROR MESSAGES -- for case where the dot (.) leads to error!
    # and we want to reply with DIFFERENT address, thus:  '.:ERROR' key.

    $(iserrormsg) &&
        tmp=$(routesdb "$domain" -: '.:ERROR') &&
            tmp=$(routes_spec "$tmp" "$address" $A) &&
                returns $tmp

    tmp=$(routesdb "$domain") &&
        tmp=$(routes_spec "$tmp" "$address" $A) &&
            returns $tmp

#| The routes_spec function interprets the return value from the
#| routesdb lookup.

    return 1
}


21.5.17. echo

Syntax:

echo [-n] [-- string-expressions... ]



Return Values:

0



Options:

-n

Don't print newline at end of string.

--

End the option set, use this if there is even a small change of starting the the data with the hyphen character.



Notes:

none

21.5.18. elements

Syntax:

elements lisp-object



Return Values:

lisp-object

Options:

none

Notes:

This does a side-effect on input list, which is need in "for" loops:

  for loopvar in $(elements $listvar)
  do
    ...
  done


21.5.19. envars

Syntax:

envars



Return Values:

0



Options:

none

Notes:

A debug tool to print internal variable tree.

21.5.20. erraddron

Syntax:

erraddron [file]



Return Values:

0

Successfull operation.

64

Wrong usage of arguments.



Options:

Optional filename.

Notes:

Without a filename this dissociates the possible pre-existing logging file definition.

With a filename option this specifies a filename into which the router appends all address parsing error messages. This is primarily for curious postmasters or other collectors of address trivia.

This is a debug tool; usage examples:

  erraddron $POSTOFFICE/postman/ERRADDRLOG

  erraddron


21.5.21. eval

Syntax:

eval expression



Return Values:

status

Options:

none

Notes:

This is the generic workhorse for self-modifying code execution within the zmsh, it creates the workhorse of following code-fragment:

# Usage: newattribute <oldattribute> <key1> <value1> [ <key2> <value2> ] ...
#
# Returns a new attribute list symbol with the <keyN> <valueN>
# attributes added to the contents of the <oldattribute> list.

newattribute (oldattribute) {
        local a null value

        a=$(gensym)
        eval $a=\$$oldattribute
        while [ "$#" != 0 ];
        do
                lreplace $a "$1" "$2"
                shift ; shift
        done
        echo -- "$a"
}


21.5.22. exit

Syntax:

exit



Return Values:

does not return, does exit(2) for the shell/router..

Options:

none

Notes:

Exit from the shell/router with exit code.

21.5.23. export

Syntax:

export [variable-name...]



Return Values:

0

??? FIXME



Options:

none

Notes:

Exports variable name(s). If no variables are given, export prints a list of which variables have been exported.

21.5.24. filepriv

Syntax:

filepriv file [uid]



Return Values:

0

??? FIXME

1

Error.



Options:

none

Notes:

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.

21.5.25. first

Syntax:

first object-reference



Return Values:

Pointer to copied lisp-object of object-reference's car operation.

Options:

none

Notes:

This command is synonymous to the car (at Section 21.5.8), and channel (at Section 21.5.12) commands.

21.5.26. gensym

Syntax:

gensym



Return Values:

0



Options:

none

Notes:

Generates and prints a new symbol name in the sequence g0 to gN every time it is called. The sequence is reset and any symbol values destroyed after the router has processed a message. This function is used to generate new symbols, to hold attached address property lists, during alias expansion.

Code-fragment showing a way how it is used inside the router scripts:

# Usage: newattribute <oldattribute> <key1> <value1> [ <key2> <value2> ] ...
#
# Returns a new attribute list symbol with the <keyN> <valueN>
# attributes added to the contents of the <oldattribute> list.

newattribute (oldattribute) {
        local a null value

        a=$(gensym)
        eval $a=\$$oldattribute
        while [ "$#" != 0 ];
        do
                lreplace $a "$1" "$2"
                shift ; shift
        done
        echo -- "$a"
}


21.5.27. get

Syntax:

get property-list keyname
get property-list-varname keyname



Return Values:

property-list

Options:

none

Notes:

Returns a property-list corresponding to key string:

  listvar=(key1 value1 keyname value key3 value3)
  result1=$(get  listvar keyname)
  result2=$(get $listvar keyname)


21.5.28. getopts

Syntax:

getopts optstring-name [arguments...]



Return Values:

0

success ?

1

Error.



Options:

none

Notes:

Never used inside the zmsh scripts, usefullness questionable, and usage documentation missing.

21.5.29. grind

Syntax:

grind lisp-object



Return Values:

Pointer to list of varcell.

Options:

none

Notes:

This is a debug tool.

The side-effect is to output the text form of the lisp-object.

21.5.30. groupmembers

Syntax:

groupmembers groupname



Return Values:

0

Found data, side-effect is described below.

1

Didn't find anything. No side-effects.

64

Usage (number of arguments) is wrong.



Options:

none

Notes:

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.

21.5.31. hash

Syntax:

hash [-r] [command names]



Return Values:

0

This value is returned always.



Options:

-r

Path is flushed.

command names

These are looked up one by one via the PATH environment variable, and results are stored into internal quick-access hash table.



Notes:

This is a part of the "zmsh" shell-script interpreter in good SH-tradition, but is not used in the ZMailer router in any way.

21.5.32. homedirectory

Syntax:

homedirectory user



Return Values:

0

Found home directory, side-effect is printing of that directory into stdout, whence it may be captured into e.g. some variable.

2

Error, no such user.

3

Error, some temporary lookup failure. Also sets "$defer" variable.

64

Usage error, wrong number of arguments. (Usage.)



Options:

none

Notes:

Prints the home directory of the specified user account.

21.5.33. host

Syntax:

host object-reference



Return Values:

The host (2nd) component of an address quad.

Options:

none

Notes:

none

21.5.34. hostname

Syntax:

hostname [name]



Return Values:

0

Returns always this value.



Options:

none

Notes:

Sets the router's idea of the system hostname. Without an argument the name is retrieved from the system and printed. The router 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.

21.5.35. ifssplit

Syntax:

ifssplit any-string



Return Values:

split list

Options:

none

Notes:

This splits given input string per IFS environment variable, and produces a list of substrings ready for further use.

21.5.36. lappend

Syntax:

lappend varname anyvalue



Return Values:

NULL; actually error cases output to stderr, all others are handled silently.

Options:

none

Notes:

This appends content of list object (anyvalue) to named varname variable:

#
# From  aliases.cf  of system standard scripts.
#

maprrouter (attribute, localpart, origaddr, plustail, domain) {
    local shh al

    al=()
    while read address
    do
        case "$address" in
        ") shh=(((error expansion "$localpart")))
            lappend al $shh
            continue
            ;;
        esac

        defer="
        shh=$(rrouter "$address" "$origaddr" $attribute \
             "$plustail" "$domain")
        [ -n "$defer" ] &&
            shh=(((hold "$defer" "$address" $attribute)))
        defer="
        lappend al $shh
    done
    returns $al
}


21.5.37. last

Syntax:

last lisp-object



Return Values:

Return a pointer to last cell of varcell's list.

Options:

none

Notes:

This is actually a unused relict from way way back..

21.5.38. length

Syntax:

length lisp-object



Return Values:

String of decimal numbers representing the number of varcell's in the lisp-object primary chain.

Options:

none

Notes:

This counts the number of elements in the chain, not length of any string.

21.5.39. list

Syntax:

list objects...



Return Values:

List-wrapped lisp-object.

Options:

none

Notes:

z# list 1 2 3
(1 2 3)
z# tt=(1 2 3)
z# list $tt
((1 2 3))
z# tt=$(list 1 2 3)
z# grind $tt
(1 2 3)


21.5.40. listaddresses

Syntax:

listaddresses [-e error-address] [-E errors-to-address] [-c comment]



The stdin feeds in the list of addresses.

Return Values:

lisp-list

Successfull processing result. There can still be an error-report sent to the error-address; see below.

NULL

Error, stderr gets an error report text, and in some cases also the "-e" defined error-address, and "postmaster" will get email telling of problems in the file.



Options:

-e

Any syntax errors at list parsing will cause a report to be mailed to the given address.

-E

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.

-c

A comment will be inserted in the error report.



Notes:

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.

21.5.41. listexpand

Syntax:

listexpand [-c comment] [-e error-address] [-E errors-to-address] [-p privilege-integer] [-N notary-string] $attribute $localpart $origaddr [$plustail [$domain]]



Return Values:

lisp-list (or NULL)

Options:

-e

Any syntax errors at list parsing will cause a report to be mailed to the given address.

-E

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.

-c

A comment will be inserted in the error report.

-p

Integer privilege code for expanded addresses

-N

Notary string data, or "-" for "no DNS".



Notes:

This implements the most common pipeline where listaddresses (at Section 21.5.40) was used with more efficient memory consumption handling. (System memory usage internals have changed over the time, and now this is no longer especially great memory expenditure saver.)

The stdin will feed addresses from a file for parsing, and parameter mapping + routing.

Comparison of previous listaddresses (at Section 21.5.40) -script implemented code, and new one using the listexpand:

Old:

    l="$preowner$(basename "$lcuser" -mod)$postowner"
    nattr=$(newattribute $attr privilege $priv sender "$l")
    $(zapDSNnotify $nattr delivered "$sender" "$lcuser$domain")
    a=$(runas $priv cat "$a" | \
        listaddresses       -E "$l$domain"          \
                            -e "$l"                 \
                            -c "$a file expansion" |
        maprrouter $nattr "$a" "$host" "$plustail"  \
                    "$domain")
    postzapDSNnotify a
    returns $a


New:

    l="$preowner$(basename "$lcuser" -mod)$postowner"
    if priv=$(getpriv "664" $priv "$a" maillist) &&
       nattr=$(newattribute $attr privilege $priv sender "$l") ; then
        $(zapDSNnotify $nattr delivered "$sender" "$lcuser$domain")
        a=$(runas $priv cat "$a" | \
            listexpand      -E "$l" -e "$l" -p $priv        \
                            -c "$a file expansion"          \
                            $nattr  "$a" "$host" "" "$domain" )
        postzapDSNnotify a
        returns $a
    fi


21.5.42. login2uid

Syntax:

login2uid username



Options:

none

Return Values:

"nobody-uid"

Either uid of "nobody", or no lookup match for given userid.

uid

UID of user.



Notes:

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 fullname in-core database, to add the login name to uid mapping to the pwnam in-core database, and to add the uid to login name mapping to the pwuid in-core database.

21.5.43. lreplace

Syntax1:

lreplace varname indexnum anyvalue



Syntax2:

lreplace varname fieldname anyvalue



Return Values:

none

Options:

none

Notes:

This replaces designated field on varname variable containing list-like data with anyvalue value.

The field designation can be given in numeric form, where the field index can be numeric (first field is zero), or keyname on key/value pair list.

If a key is not found (with key/value pairs), then designated pair is added to the list.

  z$ tt=(aa 11 bb 22 cc 33 dd 44)
  z$ grind $tt
  (aa 11 bb 22 cc 33 dd 44)
  z$ lreplace tt bb zz
  z$ grind $tt
  (aa 11 bb zz cc 33 dd 44)
  z$ lreplace tt 0 aaa
  z$ grind $tt
  (aaa 11 bb 22 cc 33 dd 44)
  z$ lreplace tt zz aa
  z$ grind $tt
  (aaa 11 bb 22 cc 33 dd 44 zz aa)

This is an example of "lreplace" use in the scripts:

# Usage: newattribute <oldattribute> <key1> <value1> [ <key2> <value2> ] ...
#
# Returns a new attribute list symbol with the <keyN> <valueN>
# attributes added to the contents of the <oldattribute> list.

newattribute (oldattribute) {
        local a null value

        a=$(gensym)
        eval $a=\$$oldattribute
        while [ "$#" != 0 ];
        do
                lreplace $a "$1" "$2"
                shift ; shift
        done
        echo -- "$a"
}

A fragment of code from inside the crossbar.cf shows different usages:

....
    usenet)
        lreplace from 2 "$(uucproute "$(user $from)")"
        tsift $(user $from) in
        $hostname!.*    ;;
        .*    
            lreplace from 2 $hostname!$(user $from)
            ;;
        tfist
        # newsgroup name only
        lreplace to 2 "$(localpart "$(user $to)")"
        ;;
....

21.5.44. malcontents

Syntax:
  malcontents


Return Values:

none

Options:

none

Notes:

ZMSH Debugging thing.

21.5.45. printaliases

Syntax:

printaliases [-v] [-o indexoutputfile] file



Return Values:

0

1

Error.



Options:

-v

Verbose.

-o indexoutputfile

Each header line will also generate a "header TAB byteoffset" line in the indexfile.

Notes:

This function was used by the "newaliases(1)" program to generate the aliases database from a source file.

That task has been moved into "zmailer newdb" (at Section 24.1.8) process, along with all other router database refreshment tasks.

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 "#" at the beginning of a line, or after an address, to the end of line.



21.5.46. process

Syntax:

process messagefile



Return Values:

0

Successfull processing.

100

File name parameter missing.

other

Return value from the underlying scripts.



Options:

none

Notes:

The protocol switch function. It is called by the "daemon" function (at Section 21.5.14) to process a message found in the $POSTOFFICE/router/ 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 MSG_RFC822 parameter to mail_open(3). For that case, the protocol function is called "rfc822".

router has a bit more complex directory semantics, than is stated above. See "zmailer(3)" for details.

Although the "process" function is provided built in, it is usually overridden by a defined function in the router configuration file. (See process.cf, and the entrypoint text at Section 21.4.1)

21.5.47. read

Syntax:

read variable...



Return Values:

0

Successful read.

1

Error. (End of input)

64

Error. Missing mandatory variable name. (Usage.)



Options:

none

Notes:

The read will get one line of input, and if there are more than one variable name parameter, split it at the whitespaces (IFS chars).

There appears to be a bug when there are less IFS separated sequences than there are varnames: The extra varnames do get things at a bit random.. (2001-Oct-15)

If input line is zero length (or all IFS chars), the read will read another input line.

If the input line ends with character: "\" as its very last, the line gets a catenation of next input line effectively unfolding multiline coded string.

z# echo "1 2 3 4 5" | read v1 v2
z# echo $?
0
z# echo $v1
1
z# echo $v2
2 3 4 5
z# echo "11111" | read v1 v2
z# echo $?
0
z# echo $v1
11111
z# echo $v2
11111


21.5.48. recase

Syntax:

recase [-u | -l | -p] -- string



Return Values:

0

Success, stdout gets the result string.

64

Bad option. (Usage.)



Options:

--

End options.

-u

Convert into uppercase.

-l

Convert into lowercase.

-p

Prettify.



Notes:

A case-mapping function that prints the parameter string in either all-uppercase, all-lowercase, or capitalized (pretty).

The input to be converted is expected to be single string, e.g. not multiple strings.

Due to internal use of "getopt" for parameter pickup, if there is even the slightest change that the string begins with a hyphen (minus) character, invocation must use the -- pair to end the options, and to protect the parameter.

Typical use in the router scripts:

   lcuser="$(recase -l -- "$user")"


21.5.49. recipient

Syntax:

recipient



Return Values:

1

Is a recipient address.

0

Is not.



Options:

none

Notes:

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

21.5.50. relation

Syntax:

Generic:

relation [-i] [-T] -t dbtype [/subtype] [-f file] [-e #] [-s #] [-:%blmnu] [-d driver] [-C configfile] name

The separator character between "dbtype" and "subtype" can be either a comma (",") or a slash ("/"), as user wishes. In case the subtype is a filepath (or otherwise begins with a slash), the user propably wants to use comma to reduce confusion.

More specific versions:

relation -t yp,yp-mapname -f yp-domain [-e #] [-s #] [-:%blmnu] [-d driver] name
relation -t bind/query-type [-f file] [-e #] [-s #] [-:%blmnu] [-d driver] name
relation -i -t ordered,filepath2 -f filepath1 [-e #] [-s #] [-:%blmnu] [-d driver] name
relation -i -t unordered,filepath2 -f filepath1 [-e #] [-s #] [-:%blmnu] [-d driver] name
relation -t ordered -f filepath [-e #] [-s #] [-:%blmnu] [-d driver] name
relation -t unordered -f filepath [-e #] [-s #] [-:%blmnu] [-d driver] name
relation -t dbtype [-f file] [-e #] [-s #] [-:%blmnu] [-d driver] name

Note: "zmailer newdb" does not support "-i" option use! (FIXME! FIXME! 2001-Mar-8)

Special support for testing of presence of support for given dbtype:

relation -T -t dbtype dummy_name



Options are listed below. name is the name of the relation that is wanted to be created. Examples:

relation -t bind,mx mxhost
relation -t ordered -f $MAILVAR/db/routes routes
relation -t ordered -b -f /usr/lib/news/active.sorted newsgroups


Return Values:

0

Relation is reated successfully, however possible database access are not tried yet.

1..7

Error.



Options:

-T

Special flag enabling script to test for given db-type:

  relation -T -t btree dummy && echo "have BTREE database"


-t dbtype[,subtype]

Below is a table to option interdependencies as they apply with different database types.

Figure 21-1. relation's option interdependencies

Db-Type Subtype meaning -f option value
incore ignored ignored
header ignored ignored
selfmatch ignored ignored
hostsfile ignored ignored (?)
ordered ignored (without -i option) path-to-file
unordered ignored (without -i option) path-to-file
ordered path-to-file-2 (with -i option) path-to-file-1
unordered path-to-file-2 (with -i option) path-to-file-1
bind DNS-query-subtype ignored
yp YP-mapname YP-domain
ldap ignored?? path-to-cfg-file
dbm ignored basepath-to-db-file
ndbm ignored basepath-to-db-file
gdbm ignored basepath-to-db-file
btree ignored basepath-to-db-file
bhash ignored basepath-to-db-file

One of the known types of databases, currently:

incore

A database maintained in virtual memory (using splay trees). This type should not be used for any database that must periodically be flushed, since all occupied memory can be freed.

header

A special incore database type used to store RFC822 header semantics information. It is unlikely to be used for anything else.

ordered

The -f-option defines the path of the file.

A file with key-value pairs on every line, separated by whitespace, sorted by key. (See sort(1).)

key_at_line_start   data at the same line


unordered

The -f-option defines the path of the file.

A file with key-value pairs on every line, separated by whitespace.

key_at_line_start   data at the same line


ordered,path-to-file-2

The -f-option defines the path of the file-1.

The version for antique "-i" mode.

unordered,path-to-file-2

The -f-option defines the path of the file-1.

The version for antique "-i" mode.

hostsfile

The -f-option defines the path of the file. (In theory...)

A rather theorethical database looking into hosts(5) database file (often /etc/hosts).

bind/query-subtype

The -f-option defines the path of the resolver configuration file. (Not implemented!)

The BIND implementation of a Domain Name System resolver. The subtype for this type is the name of a Resource Record type in the IN class.

Supported subtypes are: A, AAAA, ANY, CNAME, MX, MXLOCAL, MXWKS, PTR, TXT, UINFO, WKS

FIXME! FILL DETAILS! (About the return values)

ndbm

The -f-option defines the base path of the files, and the NDBM appends ".pag" and ".dir" to each file.

The newer DBM as created at (I think) BSD 4.2. This is two-file database with API utilizing nonglobal API, that is, multiple databases can be open simultaneously. This appends .dir and .pag to the supplied name!

Limitation: The length of key plus the length of data must not exceed 1024 bytes. With certain kinds of alias databases this may be too low limit!

dbm

The -f-option defines the base path of the files, and the DBM appends ".pag" and ".dir" to each file.

The old ATT DBM library with even worse limitations than ndbm has. Avoid if you can. (ZMailer can manage with this also, each lookup is done by opening the DB, and closing immediately afterwards.)

Some versions of ATT DBM did not contain externally callable close() function! ZMailer propably won't work at such a system anyway...

gdbm

The -f-option defines the path of the database file, the GDBM does not append anything to the name.

The GNU implementation of the new DBM library. Note: 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!

yp,mapname

The Network Information Service from Sun Microsystems Inc. (Later renamed to be NIS, the still newer NIS+ is not supported).

The mapname "subtype" passes knowledge about which YP-map the query is to be done from.

The -f-option is used to pass the YP-domain information to the interface.

btree

SleepyCat DB 1.x, 2.x, 3.x or 4.x B-Tree database

The -f-option defines the path of the database file, the SleepyCat DB does not append anything to the name. (This is true with versions 1.x, 2.x, 3.x, and 4.x.)

The -C-option defines SleepyCat DB environment configuration file, which can be used to define advanced features, mainly Concurrent Data Store function.

 FIXME! FIXME! config file!

$ cat /opt/mail/db/sleepyenv.conf 
#
# SleepyCat DB 3/4 environment settings
#

envhome  = /opt/mail/db
#tmpdir = ...
envmode  = 0600
envflags = CDB, CREATE, RO


bhash

SleepyCat DB 1.x, 2.x, 3.x or 4.x HASH database

The -f-option defines the path of the database file, the SleepyCat DB does not append anything to the name. (This is true with versions 1.x, 2.x, 3.x, and 4.x.)

The -C-option defines SleepyCat DB environment configuration file, which can be used to define advanced features, mainly Concurrent Data Store function.

 FIXME! FIXME! config file!

$ cat /opt/mail/db/sleepyenv.conf 
#
# SleepyCat DB 3/4 environment settings
#

envhome  = /opt/mail/db
#tmpdir = ...
envmode  = 0600
envflags = CDB, CREATE, RO


selfmatch

Given address literal without wrapping square brackets, this "database" decodes the address, and checks if presented IP address is one used by the system at the moment.

ldap

FIXME! WRITEME!



-f file

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.

-e #

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.

-s #

Sets the cache size to the specified number. The default is usually 10, depending on the database type.

-b

If the key exists in the database, return the key as the value. ("Boolean relation")

-i

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 was used for the aliases file back in early 1990, and is usable only with ordered, and unordered database types.

(FIXME! IMPLEMENT? To think of it, this makes eminently sense also for dbm, and ndbm which have data size limitations. But then, SleepyCat DB is recommended for internal databases anyway.)

-l

Map all keys to ASCII lowercase before searching.

-m

Check for file content modification before every access. Reopen the file when a change is detected.

This option is used when the router 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 mmap(2) facility. Updating such databases should preferably use mv command to move a new version of the database in place of the old one.

-n

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.

-u

Map all keys to ASCII uppercase before searching.

-d [pathalias|pathalias.nodot|longestmatch]

Specifies a search driver that allows searching for structured keys using special knowledge. The argument to this option must be a known driver.

FIXME! WRITEME! WRITE MORE!

-%

We shall do positional parameter substitutions ("%0" thru "%9") on database lookup result data. [XREF??]

The zmailer newdb configuration file $MAILVAR/dbases.conf uses presence of "%" to signal this aspect of relation wrapper generation. [XREF??]

-:

Actually this is ignored if present, the zmailer newdb configuration file $MAILVAR/dbases.conf uses presence of ":" to signal certain aspects of relation wrapper generation. [XREF??]



Notes:

On systems with USE_MMAP 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.)

21.5.51. rest

Syntax:

rest object-reference



Return Values:

Pointer to copied lisp-object of object-reference's cdr operation.

Options:

none

Notes:

This command is synonymous to the cdr command (at Section 21.5.11).

21.5.52. return

Syntax:

return lisp-object



Return Values:

lisp-object

The argument lisp-object contains a non ASCII digit character, or is a complex lisp-object.

string

The argument lisp-object contains a non ASCII digit character, and is a simple string-object.

statuscode

The argument lisp-object contains a all ASCII digit characters, and is a simple string-object.

See the Notes below about this, too.

NULL

Invalid lisp-object.



Options:

none

Notes:

The system has a weird dichtomy on returning numeric vs. other results.

Presume a function call with two different possible results, failure indication, and successfull (arbitrary) string result:

  tmp=$(funcnnn args..) && returns $tmp
  return $tmp  # error code return!


21.5.53. returns

Syntax:

returns lisp-object



Return Values:

lisp-object

This one will always return the lisp object without interpreting possible string value to be numeric return code.



Options:

none

Notes:

See notes of "return" above.

21.5.54. rfc822

Syntax:

rfc822 messagefile



Return Values:

status

Options:

none

Notes:

This function controls the parsing and processing of the message file in RFC822/976/2822 format. It is called by the process function (at Section 21.5.46). .

21.5.55. rfc822date

Syntax:

rfc822date



Return Values:

0

Side effect: stdout gets current time string printed in RFC822/2822 format.



Options:

none

Notes:

Prints the current time in RFC822/2822 format.

21.5.56. rfc822syntax

Syntax:

rfc822syntax address



Return Values:

0

Given input matches RFC 822/976/2822 for "route-address" syntax specification.

1

Error. Given input is syntactically somehow invalid.

64

Argument count is not exactly 1. (Usage.)



Options:

none

Notes:

This is a simple interface to the address parser. If the command line argument is a syntactically valid RFC822/976/2822 address, this command is silent and returns 0 as status. If there is a parse error, a verbose error message is printed to stdout and the function yields a non-zero return status.

21.5.57. runas

Syntax:

runas user function [arguments...]



Return Values:

Any of the values yielded by the executed "function", or:

0

Internal evaluation of "function" did yield 0.

1

Setting target uid failed.

64

Mandatory parameters missing. (Usage.)

abort

Resetting target uid to system uid (root) failed.



Options:

none

Notes:

Changes the current effective user id of the router 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).

21.5.58. sender

Syntax:

sender



Return Values:

1

Is a sender address.

0

Is not sender address.



Options:

none

Notes:

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

21.5.59. set

Syntax:

set [-a | -e | -f | -h | -n | -t | -u | -v | -x | -L | -C | -P | -S | -k] [-] [variable]

Without parameters set prints variable values.

Return Values:

Pointer to copied structure of car operation.

Options:

-a

Automatically export changed variables.

-e

Exit on error exit status of any command.

-f

Disable filename generation (no globbing).

-h

Hash program locations.

-n

Read commands but do not execute them.

-t

Read and execute one command only.

-u

Unset variables are error on substitution.

-v

Print shell input lines as they are read.

-x

Print commands as they are executed.

-L

Trace LEXER processing (sslWalker).

-C

Print branch and emit inputs (sslWalker).

-P

Trace execution (sslWalker).

-S

Print input buffers when used (sslWalker).

-k

Not supported option.

-

Do nothing.



Notes:

none

21.5.60. shift

Syntax:

shift [number]



Return Values:

0

Success.

1

Error, out of parameters to shift.



Options:

none

Notes:

Modifies caller's argument vector by shifting left one (or specified number) of argument(s) in current ARGV.

21.5.61. sleep

Syntax:

sleep number



Return Values:

0

Did sleep a bit, does not tell is anybody interrupted the sleep.

64

Missing mandatory integer argument. (Usage.)



Options:

none

Notes:

Does not tell if the sleep has been interrupted somehow.

21.5.62. squirrel

Syntax:

squirrel [-]event



Return Values:

0

1

Error.



Options:

-

Set flag value to 0.

(none)

Set flag value to 1.

The events are:

  • breakin

  • badheader

  • illheader

  • nochannel

  • nosender





Notes:

Sets the kinds of events that cause a message to be copied into the $POSTOFFICE/postman/ directory. Whether or not a "-" 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:

z# squirrel
Usage: squirrel [ breakin | -badheader | illheader | nochannel | nosender ]


21.5.63. stability

Syntax:

stability [on | off]



Return Values:

0

Did the work successfully.

64

Bad parameters. (Usage.)



Options:

none

Notes:

Determines whether the router will process incoming messages in arrival order (when on), or in random order determined by position in the router directory. The router 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.

21.5.64. "test", "["

See: "[", a.k.a. "test" at Section 21.5.3.

21.5.65. times

Syntax:

times



Return Values:

0

Prints to stdout the spent usermode time for process itself, and to all of its children.

1

Error in times(2) system call.

64

Usage error (no parameters allowed.)



Options:

none

Notes:

Prints to stdout the spent usermode time for process itself, and to all of its children.

Sample output:

    12m33s  22m59s


21.5.66. trace

Syntax:

trace key1 ... keyN
untrace key1 ... keyN

Enables tracing of the specified items. The valid keywords are listed in the options below.

Return Values:

0

Successful setting/clearing.

64

Parameter name error. (Usage.)



Options:

all

Turns on all tracing options.

You only do this to test the I/O capabilities of your system. (rfc822, and regexp options generate a lot of output!)

assign

Prints shell variable assignments.

bind

Prints various information from the code that calls the DNS resolver.

compare

Prints *sift statement pattern-selector comparisons.

db

Prints database lookups, including cache search and update information.

except

Inverts the sense of what is being done; e.g.:

  trace all except rfc822 regexp
which is (nearly) exquivalent of:
  trace all
  untrace rfc822 regexp


final

Prints the message envelope information after processing each message.

functions

Prints shell function calls and return values, with nesting indicated by indentation.

matched

Prints *sift statement pattern-selector matches.

memory

Prints memory allocation information after each message.

on

Same as functions -option.

regexp

Prints regular expression matching execution.

resolv

Turns on the RES_DEBUG flag in the BIND resolver library, and prints various information from the code that calls the DNS resolver.

rewrite

Prints the tokenized addresses sent through the message header address rewriting functions.

router

Prints the tokenized addresses sent through the router function.

sequencer

Prints the procedural steps taken during message processing.



Notes:

Authors most common "trace" incantation has been wrapped into standard script routine:

#|
#|  I kept typing in this trace command so frequently, that eventually
#|  I just had to make for it into a single command... /Matti Aarnio
#|

rtrace () {
        trace all except rfc822 regexp
}


21.5.67. trap

Syntax:

trap [ [script trap_nro] ...]



Return Values:

0

Set successfully, or displayed successfully.



Options:

none

Notes:

If no parameters are given, trap prints all known traps.

In all aspects this is quite alike any bourne-shell "trap" function.

Set, and unset a trap:

  trap "db flush aliasesdb ; log flushed aliases" 16
  trap "" 16


21.5.68. type

Syntax:

type [command...]



Return Values:

0

Always returns this value.

The stdout gets the report.



Options:

none

Notes:

z# type trap
trap is a shell builtin
z# type foobar
foobar not found
z# foobar () {echo foo}
z# type foobar
foobar is a shell function
z# type rfc822
rfc822 is a shell builtin
z# type process
process is a shell function
z# echo $?
0
z# type no-such-thing
no-such-thing not found
z# echo $?
0
z# type
z# echo $?
0


21.5.69. uid2login

Syntax:

uid2login uid



Return Values:

0

Argument count ok, and "uid" begins with a digit.

The stdout gets the username.

64

Parameter error. (Usage.)



Options:

none

Notes:

Prints the first account name associated with a specified numeric user id, if any, or "uid#uid" if no account exists with that user id. It has the same side-effects as the login2uid function (at Section 21.5.42).

21.5.70. umask

Syntax:

umask [octal-number-mask]



Return Values:

0

Successfull printing of the octal value, or setting new umask(2) value.

64

Parameter error. (Usage.)



Options:

none

Notes:

Without parameters the new default mask is 077, and old is printed.

21.5.71. unset

Syntax:

unset [variable...]



Return Values:

0

Had enough parameters, executed something, and possibly complained something to "stderr".

64

Missing mandatory (at least one) argument. (Usage.)



Options:

none

Notes:

This throws away named variables from all variable scopes.

z# echo $TERM
xterm
z# unset TERM
z# echo "'$TERM'"
''


21.5.72. untrace

Syntax:

trace key1 ... keyN
untrace key1 ... keyN

Disables tracing of the specified items. This is inverse of trace (at Section 21.5.66).

Return Values:

0

Successfull clearing/setting

64

Parameter name error. (Usage.)



Options:

See the trace function (at Section 21.5.66) for valid keywords.

Notes:

See the trace function (at Section 21.5.66) for valid keywords.

21.5.73. user

Syntax:

user object-reference



Return Values:

The next-address (3rd) component of and address quad.

Options:

none

Notes:

This is essentially same as:

   $(cdr $(cdr $(cdr $addrquad)))


21.5.74. wait

Syntax:

wait [pid]



Return Values:

Besides of the return codes of processes being waited, this can yield:

0

no more processes

64

Bad parameters. (Usage.)



Options:

none

Notes:

none

Chapter 22. Scheduler Reference

... deeper details of internal protocols and algorithms
 - Configuration Language Syntax Details (?)
 - Resource Management
 - What and how  scheduler.auth  can be tuned
   - Security issues
 - Diagnostics reporting, canned messages (forms/* files)
 - (MAILQv1/)MAILQv2 protocol for MAILQv2 client writer
 - Scheduler-TA interface


The scheduler daemon manages the delivery processing of messages in ZMailer.

The router creates message control files in the $POSTOFFICE/transport/ directory. These refer to the original message files in the $POSTOFFICE/queue/ directory.

The scheduler reads each message control file from $POSTOFFICE/transport/, translates the contained message and destination information into internal data structures.

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

At the time scheduled for a particular transport agent invocation, the scheduler 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 scheduler performs error reporting tasks if any, and then deletes the message control file in $POSTOFFICE/transport/ and the original message file in $POSTOFFICE/queue/.

All message delivery is actually performed by Transport Agents, which are declared in a configuration file for the scheduler. Each transport agent is executed with the same current directory as the scheduler. The scheduler-transporter 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 scheduler.

Two types of reports are produced:

  1. 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 scheduler generates an error message to the error return address of the message (usually the original sender).

  2. The scheduler binds itself to a well-known TCP/IP port (MAILQ, TCP port 174) 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 scheduler 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 mailq(1) program serves this purpose.



Usage:

Invoking scheduler without any parameter will start it as a daemon.

scheduler [-dinvFHQSVW] [-E newentsmax] [-f configfile] [-l statisticslog] [-L logfile] [-N transpmaxfno] [-p channel/host-pair] [-P postoffice] [-q rendezvous] [-R maxforkfreq]



Parameters:
-d

run as a daemon, usually used after -v to log daemon activity in great detail.

-E newentsmax

when globbing new tasks from the directory, pick only first newentsmax of them, and leave rest for a latter scan run.

-f configfile

overrides the default configuration file $MAILSHARE/scheduler.cf.

-F

Freeze -- don't actually run anything, just do queue scanning. (For debug purposes..)

-H -HH

Use multi-level hashing at the spool directories. This will efficiently reduce the lengths of the scans at the directories to find some arbitrary file in them. One H means single level hashing, two HH mean dual level hashing. Hash is directory which name is single upper case alphabet (A-Z).

-i

run interactively, i.e., not as a daemon.

-l statisticslog

starts the appending of delivery statistics information (ASCII form) into given file. No default value.

-L logfile

overrides the default log file location $LOGDIR/scheduler.

-n

Toggles the configuration flag called “default_full_content”, which defines what will be “DSN RET” parameter assumed value in case the originator didn't supply that parameter.

The default behaviour is similar to “RET=FULL”, while usage of this option is equivalent of “RET=HDRS”.

This option does not override originator supplied DSN RET parameter value.

-N transmaxfno

sets how many filehandles are allocated for the scheduler's started children (if the system has adjustable resources.)

-p channel/host

A debug option for running selectively some thread under a single instance of the scheduler.

Use this option with -v.

-P postoffice

specifies an alternate $POSTOFFICE/ directory.

-q rendezvous

the rendezvous between machines without TCP/IP networking,

Scheduler and mailq(1) is done using a well-known named pipe. This option overrides the default location for this special file, either $RENDEZVOUS or /usr/tmp/.mailq.text. (not used in real life; aspect of ZMailer's support for low-tech things..)

-Q

The Q-mode, don't output the old style data into the queue querier, only the new-style one.

-S

Synchronous startup mode, scans all jobs at the directory before starting even the first transporter.

-v

Verbose logging in interactive mode -- for debug uses.

-V

Print version, and exit

-W

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.

22.1. Configuration Language

\index{{\tt scheduler.conf} file}\index{scheduler, {\tt scheduler.conf}}

The scheduler configuration file consists of a set of clauses.

There are two kinds of clauses:

  • PARAM-entries

  • Group-Clause selections



22.1.1. PARAM-entries

There are three kinds of PARAM entries, all of them start at the column number 0 (left edge):

#
# MAILQv2 authentication database file reference:
# If you define this (like the default is), and the file exists,
# scheduler mailq interface goes to v2 mode.
# (Nonexistence of this file  A) leaves system running, B) uses MAILQv1
#  interface along with its security problems.)
#

PARAMauthfile = "${MAILSHARE}/scheduler.auth"

#PARAMmailqsock = "UNIX:/path/to/mailq.sock"
#PARAMmailqsock = "TCP:174"

# Time for accumulating diagnostic reports for a given message, before
# all said diagnostics are reported -- so that reports would carry more
# than one diagnostic in case of multi-recipient messages.
#PARAMglobal-report-interval = 15m


The PARAMauthfile defines Scheduler's MAILQv2 authentication file; more at Section 22.3.

The PARAMmailqsock defines non-standard socket for the MAILQv2, the default is “TCP:174” meaning local host binding on wild-card address, and port 174 of TCP. Other ports and protocols can be set. The mailq tool will not parse this file to know where to connect.

The PARAMglobal-report-interval is how often (or infrequently) to run the scheduler's subtask of reporting so far accumulated diagnostics. Original behaviour was to report diagnostics only when message timed out, or last recipient was otherwise disposed of. Current method is somewhat quicker.

22.1.2. Group-Clause selection

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:

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"


A clause consists of:

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

  • 0 or more variable assignments or keywords (described below).



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 “*”.

22.1.3. Clause components

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:

  • a clause matching all addresses (using the pattern “*/*”) that sets up default values.

  • a clause matching the local delivery channel (usually “local”).

  • a clause matching the deferred delivery channel (usually “hold”).

  • a clause matching the error reporting channel (usually “error”).

  • clauses specific to the other channels known by the router, for example, “smtp” and “uucp”.



The actual names of these channels are completely controlled by the router configuration file.

Empty lines, and lines whose first non-whitespace character is “#”, 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:

   1h5m20s


22.1.4. Variables and keywords

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

ageorder

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.

bychannel

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 $channel occurs in the command, but may also be specified manually by this keyword. This is rarely used.

command="sss"

is the command line used to start a transport agent to process the address. The program pathname is specified relative to the $MAILBIN/ta/ directory.

The string $channel is replaced by the current matched channel, and $host replaced by the current matched host, from the destination address.

It is strongly recommended that the $host is not to be used on a command definition, as it limits the re-usability of idled transporter.

It is possible to place environment-string setting statements into the beginning of the line:

  command="MALLOC_DEBUG_=1 OTHER=var cmdname cmdparams"


expiry=nn (3d)

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.

group="sss" (daemon)

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

idlemax=nn (3x interval)

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

interval=nn (1m)

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.

maxchannel=nn (0), (maxchannels=nn)

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.

maxring=nn (0), (maxrings=nn)

Recipients are groupped into threads, and similar threads are groupped into thread-rings, 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.

maxta=nn (0)

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[1] is used instead.

maxthr=nn (1)

This limits the number of parallel transport agents within each thread; that is, using higher value than default “1”

nice=nn

Defines relative priority value for transport-agent process. Default is not to use this. Value range in between -40 to 40.

overfeed=nnn (0)

Max number of tasks to feed from the thread to the transporter agent when feeding jobs to it. The scheduler main-loop at the mux() is a bit sluggish, thus with this we can keep the transporters busy.

The default is defined at the */* clause.

priority=nn

Defines absolute priority value for transport-agent process. Default is not to use this. Value range in between -20 to 20.

queueonly

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

To have message expiration working, following additional entries are suggested:

  interval=1h
  retries="24"
That is, retry once in a day.

reporttimes="n n n" ()

Placeholder for DELAYED reporting mechanism.

retries="n n n" (1 1 2 3 4 8 13 21 34)

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"):

      retries=0
    


  • constant primary interval:

      retries=1
    


  • instant backoff:

      retries="1 50 50 50 50 50 50 50 50 50 50 50 50"
    


  • slow increasing (fibonacci) sequence:

      retries="1 1 2 3 5 8 13 21 34"
    


  • s-curve sequence:

      retries="1 1 2 3 5 10 20 25 28 29 30"
    


  • exponential sequence:

      retries="1 2 4 8 16 32 64 128 256"
    


  • etc.



skew=nn (5)

Leftover of earlier scheduler internal algorithms, does not make sense anymore.

sysnice=nn

Can be used (if desired) at the */* clause to set relative niceness for the scheduler process, and all of its children.

syspriority=nn

Can be used (if desired) at the */* clause to set absolute priority for the scheduler process, and all of its children.

user="sss" (root)

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

wakeuprestartonly

Start only one instance of handling processes, never mind what other settings say.



For example, this is a complete configuration file:

# 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"


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 (“smtp/*.toronto.edu”) 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 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 “$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.

22.2. Resource Management

For resource management there are following configuration attributes:

maxta=nn

Max number of transporter processes under the scheduler.

maxchannel=nn

Max number of processes with this same “channel”.

maxring=nn

Max number of processes with this set of threads.

maxthr=nn

Max number of processes at any given thread in this set of threads.

idlemax=time

How long the non-active (idle) transporter processes are allowed to keep around.

overfeed=nnn

Max number of tasks to feed from the thread to the transporter agent when feeding jobs to it. The scheduler main-loop at the mux() is a bit sluggish, thus with this we can keep the transporters busy.



22.3. scheduler.auth file

The file whose default boilerplate is shown at Figure 22-1 is able to control what kind of things (and who, of those who know shared secrets) can ask the scheduler to do via the so called “MAILQv2” protocol.

Figure 22-1. Sample of scheduler.auth file

#
# APOP-like authentication control file for the ZMailer scheduler.
#
# Fields are double-colon (':') separated, and are:
#   - Username
#   - PLAINTEXT PASSWORD (which must not have double-colon in it!)
#   - Enabled attributes (tokens, space separated)
#   - Addresses in brackets plus netmask widths:  [1.2.3.4]/32
#
# Same userid CAN appear multiple times, parsing will pick the first
# instance of it which has matching IP address set
#
# The default-account for 'mailq' is 'nobody' with password 'nobody'.
# Third field is at the moment a WORK IN PROGRESS!
#
# SECURITY NOTE:
#   OWNER:      root
#   PROTECTION: 0600
#
# Attribute tokens:
#       ALL     well, a wild-card enabling everything
#       SNMP    "SHOW SNMP"
#       QQ      "SHOW QUEUE SHORT"
#       TT      "SHOW QUEUE THREADS", "SHOW THREAD channel/host"
#       ETRN    "START THREAD channel host"
#       KILL    "KILL THREAD channel host", "KILL MSG spoolid"
#
# - "nobody" via loopback gets different treatment from
#   "nobody" from anywhere else.
#
nobody:nobody:SNMP QQ TT ETRN:  [127.0.0.0]/8 [ipv6.0::1]/128
nobody:nobody:SNMP ETRN:        [0.0.0.0]/0   [ipv6.0::0]/0
#watcher:zzzzz:SNMP QQ TT ETRN: [127.0.0.0]/8 [192.168.0.1]/32
#root:zzzzzzz:ALL:              [127.0.0.0]/8 [192.168.0.2]/32

22.4. mailq protocol v.1

FIXME! FIXME!

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

The TCP stream syntax is:

version id\n
data in id-dependent format<close>


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 “zmailer 1.0”. For that data format, the syntax of the data following the first LF is:

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)+)?


Where:

\n

is an ASCII linefeed

\t

is an ASCII tab

key

is an unsigned decimal number

msg-file

is a contiguous string (it is the message file name relative to a known directory)

n-addrs

is an unsigned decimal number (number of addresses)

off1...offN

are unsigned decimal numbers (address byte offsets)

text

is a string not containing an ASCII linefeed (status message)

word

is a contiguous string (a “contiguous string” is a sequence of printable non-space characters



For example, here is sample output from connecting to the MAILQ port:

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


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.

22.5. mailq protocol v.2

FIXME! FIXME!

22.6. Transport Agent Interface Protocol

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:

(start the transport agent)
#hungry                --> (TA to scheduler)
spoolid \t hostspec    <-- (scheduler to TA)
diagnostics            --> (TA to scheduler)
#hungry                --> (TA to scheduler)
...


Normal diagnostic output is of the form:

  id / offset \t notarydata \t status message
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,

notarydata

is a Ctrl-A separated tuple is delivery-status-notification information for the message,

status

is one of:ok, ok2, ok3, error, error2, deferred, retryat

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 retryat 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 UNIX epoch.

The exit status is a code from <sysexits.h>.

22.7. Canned (Error) Message Files

FIXME! TEXT TO BE INSERTED HERE.

22.8. Security Issues

FIXME! TEXT TO BE INSERTED HERE.

Chapter 23. Transport Agents References

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.

23.1. mailbox

- All options
- Internal Logic
- Tuning issues
- Customizability
- Logging ? (or move that to ADM?)


The mailbox is a ZMailer transport agent which is usually only run by the scheduler(8) program to deliver mail to local user mailbox files. The mailbox program must be run with root privileges and invoked with the same current directory as the scheduler, namely: $POSTOFFICE/transport/.

Recipient addresses are processed as follows:

  • Strip doublequotes around the address, if any.

  • Strip prefixing backslashes, if any.

  • If the address starts with a “|”, the rest of the recipient address string is interpreted as a shell command to be run.

  • If the address starts with a “/”, the recipient address is a filename to append the message to.

  • Otherwise the recipient address must be a local user id.

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



If delivering to a user mailbox ($MAILBOX/userid) which does not exist, mailbox will try to create it. If the $MAILBOX/ 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:

  • The file being delivered to must have one link only, and must be either /dev/null or a regular file.

  • The file lock must be held. (See below for a chapter about locks.)



There is a further sanity check on mailbox deliveries, namely if the mailbox is not empty the mailbox program will enforce 2 newlines as a separator before the message to be delivered. This guarantees that User Agents, like Mail(1), 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 $PATH, $SHELL, $HOME, $USER, $SENDER, $UID environment variables. The $HOME and $USER values are the recipient user's home directory and login id respectively. The $SENDER 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 are 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 .rbiff file in their home directory. (Unless an -DRBIFF_ALWAYS compile option is used.)

Usage:

mailbox [-8] [-M] [-c channel] [-h localpart] [-l logfile] [-VabrH]



Parameters:

-c "channel"

specifies which channel name should be keyed on. The default is "local".

-h "localpart"

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

-l "logfile"

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.

-V

prints a version message and exits.

-a

the access time on mailbox files is, by default, preserved across delivery, so that programs such as login(1) can determine, if new mail has arrived. This option disables the above action.

-b

disables biff notification.

-r

disables remote biff notification (if supported).

-8

enables the MIME-QP-decoder to decode incoming MIME-email with Quoted-Printable encoded characters.

-M

enables the creation of MMDF-style mail-folder in the incoming mail folder. The default is “classic” UNIX-style folder.



Interface:

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:

id/offset<TAB>notify-data<TAB>status message
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 <sysexits.h>.

Locks:

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 $MBOXLOCKS in which the following characters have the meanings:

:

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

.

For mailboxes only: Does “dotlock” (userid.lock), or (on Sun Solaris) the maillock() mechanism.

F

If the system has flock() system call, uses it to lock the entire file. (Ignored on systemswithout flock())

L

If the system has lockf() system call, uses it to lock the entire file. (Ignored on systems without lockf())



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

The default for lockf() capable systems is: MBOXLOCKS=".L:L".

You can choose insane combinations of lock mechanisms, which on some systems cause locks to fail always, like on Linux-2.0 series where programs must not use both lockf() and flock() locks. It is extremely important that selected locking methods are consistent throughout the system with all programs trying to acquire locks on mail spools.

Environment:

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

Security:

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 /bin/sh 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 ~/.forward- or other aliasing analysis. (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 getpwuid(uid). 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.

Subprogram Envonmrm´e:

The mailbox sets the following eight environment variables for the subprograms it runs in the pipes:

HOME

The home directory path is taken from abovementioned getpwuid() lookup.

USER

Likewise the textual username.

SENDER

is the incoming “MAIL FROM:<..>” address without brackets. For an incoming error message, value “<>” is used.

ORCPT

when present, is the XTEXT encoded ORCPT value received at the message injection into this system. See RFC 1891 for details.

ENVID

when present, is the XTEXT encoded ENVID value received at the message injection into this system. See RFC 1891 for details.

ZCONFIG

is the location of the ZMailer ZENV file.

MAILBIN

is the value from ZENV.

MAILSHARE

is the value from ZENV.



23.2. hold

- All options
- Internal Logic
- Tuning issues
- Logging ? (or move that to ADM?)


hold - zmailer deferred processing transport agent

Description:

hold is a ZMailer transport agent which is usually only run by the scheduler(8) 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: $POSTOFFICE/transport/.

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 router. The condition specification contains a general condition class name followed by colon followed by a parameter string. The currently supported condition classes are:

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.

timeout

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

io

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

script

runs the named shell script with the optional given argument. The parameter is a simple name, the shell script name within the $MAILBIN/bin/ directory, optionally followed by a slash followed by an argument to be passed to the shell script.



For example:

  NS:nic.ddn.mil/cname
  TIMEOUT:649901432
  IO:error
  SCRIPT:homedir/joe


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.

Description:

{\bf Usage} \begin{verbatim} hold [ -c channel ] [ -V ] \end{verbatim}

Description:

{\bf Parameters} {\tt -c channel} specifies which channel name should be keyed on. The default is hold. {\tt -V} prints a version message and exits.

Interface:

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:

  id/offset/status message
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 <sysexits.h>;.

23.3. smtp

- All options
- Internal Logic at conversions
- SMTP vs. LMTP
- Tuning issues
- Logging ? (or move that to ADM?)


smtp - zmailer SMTP client transport agent

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

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.

Usage:

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


Parameters:

-7

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

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

-c channel

specifies which channel name should be keyed on. The default is smtp.

-d

turns on debugging output.

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

-e

use the “EHLO”-greeting only if the remote server initial banner reports “ESMTP” on it.

-h host

specifies the hostname for the SMTP HELO greeting. The default is the hostname of the local system, as returned by gethostname(2) or uname(2).

-F forcedest

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

-H

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

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

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

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

-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 ps(1).

-x

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

-P

disable SMTP-PIPELINING usage (ESMTP keyword: PIPELINING)

-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 large, at least 10 minutes.

-V

prints a version message and exits.

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



Interface:

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:

  id/offset<TAB>notify-data<TAB>status message
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 <sysexits.h>.

Extended SMTP:

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 to “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.

23.4. sm - zmailer Sendmail compatible transport agent

- ALL options, comparison against sendmail M-flags
- Internal Logic (incl. conversions)
- Tuning issues
- Logging ? (or move that to ADM?)


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

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 <sysexits.h>. 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.

Usage:

sm [-8] [-H] [-Q] [-V] [-f configfile] -c channel -h host mailer



Parameters:

-8

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

-Q

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.

-f configfile

specifies the name of a configuration file containing specifications of the various known sendmail compatible mailer programs: how to invoke them and how to process messages for them. The default is $MAILSHARE/sm.cf.

-c channel

specifies which channel name should be keyed on. There is no default. If this option is not specified, the -h option must be.

-h host

specifies which host name should be keyed on. There is no default. If this option is not specified, the -c option must be.

-h host

prints a version message and exits.



23.4.1. configuration of sm

sm is a ZMailer's sendmail(8) compatible transport agent to deliver messages by invoking a program with facilities and in a way compatible with a sendmail(8) MTA.

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 #include <sysexits.h>. 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:

sm [-8] [-H] [-Q] [-V] [-f configfile] -c channel -h host mailer



Configuration:

The configuration file $MAILSHARE/sm.conf 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(8). It 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 # are ignored, and all others are assumed to follow format shown in figure Figure 23-1.

Figure 23-1. Sample sm.conf file

#
# M          F =     P =                             A =
# the following entries are in active use at this site:
uucp        U   /usr/bin/uux          uux - -r -a$g -gC $h!rmail ($u)
usenet      m   ${MAILBIN}/ta/usenet  usenet $u
#
bitbucket   -  @MAILBIN@/ta/bitbucket  bitbucket
#
#
# bitnet stuff F=hu not set?
#
bsmtp3      snmSX /usr/local/funetnje/bmail bmail -b $h $g $u
bsmtp3rfc   snmSX /usr/local/funetnje/bmail bmail -b $h $g $u
bsmtp3nd    snmSX /usr/local/funetnje/bmail bmail -nd $h $g $u
bsmtp3ndrfc snmSX /usr/local/funetnje/bmail bmail -nd $h $g $u
defrt1      snS   /usr/local/funetnje/bmail bmail $g $u
bitnet2     snS   /usr/local/funetnje/bmail bmail $g $u
#
# the following entries are included to illustrate other possibilities
#
#local  mS  /usr/lib/mail/localm            localm -r $g $u
cyrus   Pn  /usr/cyrus/bin/deliver          deliver -e -m $h -- $u
#           # CYRUS example from: Tom Samplonius <tom@sdf.com>
procm sSPfn @PROCMAIL@      procmail -a $h -d $u
#           # Procmail example from: Ken Pizzini <ken@spry.com>
#
#prog  -    /bin/sh                         sh -c $u
#tty   rs   /usr/local/to                   to $u
#ean   mn   /local/lib/ean/mailer           mailer -d $u
#test  n    /local/lib/mail/bin/test        test $u
#

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. One or more 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 sendmail (of 5.x era..) flags are recognized, but the ones that do not make sense in the context of ZMailer will produce an error (or some are ignored). The flags that change the behaviour of sm are:

b

will activate BSMTP-type wrapping with a “hidden-dot” algorithm; e.g. quite ordinary SMTP stream, but in “batch mode”.

B

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

E

will prepend > to any message body line starting with From. (Read: “From-space”)

f

adds -f sender arguments to the delivery program.

n

will not prepend a From-line (normal mailbox separator line) to the message.

r

adds -r sender arguments to the delivery program.

S

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.

m

informs sm that each instance of the delivery program can deliver to many destinations. This affects $u expansion in the argument list, see below.

P

prepends a “Return-Path:” header to the message.

U

will prepend a From-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.

R

use CRLF sequence as end-of-line sequence. Without it, will use LF-only end-of-line sequence.

X

does SMTP-like “hidden-dot” algorithm of doubling all dots that are at the start of the line.

7

will strip (set to 0) the 8th bit of every character in the message.



The path field specifies the location of the delivery program. Relative pathnames are allowed and are relative to the $MAILBIN/ 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:

$g

which is replaced by the sender address.

$h

which is replaced by the destination host.

$u

which is replaced by the recipient address. If the m mailer flag is set and there are several recipients for this message, the argument containing the $u will be replicated as necessary for each recipient.



23.5. expirer

- All options
- Internal Logic
- Tuning issues
- Logging ? (or move that to ADM?)


FIXME! FIMXE! write me.. (about the tool to kill out messages from the queue)

23.6. libta - Transport Agent Support Library

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

23.6.1. Function groupings

Transport agent support library function groups are:

  • Message file manipulation routines.

  • Diagnostics routines.



23.6.2. Function listings

Text to be inserted here.

23.6.3. Function usage examples

Text to be inserted here.

23.7. Security Issues

Text to be inserted here.

Chapter 24. ZMailer Utilities Reference

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

24.1. zmailer command script

The zmailer command script is a wrapper for driving various sub-utilities, and in some cases, honouring flags like “freeze-state”, which administrator may set to keep system down over reboots while some maintenance acitivity is under way.

Plain zmailer command is synonymous to zmailer start.

24.1.1. zmailer bootclean

This removes all internal process reference PID files from $POSTOFFICE/ directory.

Highly recommended for your system startup scripts before starting servers

24.1.2. zmailer start

Without further parameters this starts the entire ZMailer system by starting subservers: smtpserver, router, and scheduler.

Giving parameter (one or more of subsystem names above) (re)starts just that (or those) subsystem(s).

If the system is in “frozen” state, start fails. See zmailer freeze below.

24.1.3. zmailer stop, zmailer kill

Without further parameters, this terminates the main daemons of the ZMailer (smtpserver, router, and scheduler) by sending SIGTERM to them.

Giving parameter (one or more of subsystem names above) stops just that (or those) subsystem(s).

24.1.4. zmailer nuke

Without further parameters, this kills the main daemons of the ZMailer. (smtpserver, router, and scheduler) by sending SIGKILL to them.

Giving parameter (one or more of subsystem names above) stops just that (or those) subsystem(s).

24.1.5. zmailer router

Synonym to zmailer start router, (re)starts the router process(es).

24.1.6. zmailer scheduler

Synonym to zmailer start router, (re)starts the scheduler process.

24.1.7. zmailer smtp(server)

Synonym to zmailer start smtpserver, (re)starts the smtpserver process.

24.1.8. zmailer newdb

A complicated subsystem on its own merits used to re-generate router configuration data for various database lookups.

This runs utility called newdbprocessor with its only argument of $MAILVAR/db/dbases.conf.

24.1.9. zmailer newal(iases)

Re-generates aliases database, wrapper of newaliases, and superceded by zmailer newdb.

24.1.10. zmailer newf(qdnaliases)

Re-generates fqdnaliases database, wrapper of newfqdnaliases, and superceded by zmailer newdb.

24.1.11. zmailer new-route(s)

Compiles routes database, and superceded by zmailer newdb.

24.1.12. zmailer new-local(names)

Compiles localnames database, and superceded by zmailer newdb.

24.1.13. zmailer logsync

A special command sending signals to subsystems needing them for reopening their possibly long-living logfile opens.

To be used after other methods have rotated the logfiles to new names, but before anything further is done to them.

These days only the scheduler needs it, and if you have a choice, use this only after the “scheduler” logfile is rotated.

24.1.14. zmailer logrotate

Runs ZMailer sub-utility “rotate-logs.sh”.

24.1.15. zmailer resubmit

Moves files from $POSTOFFICE/deferred/ to main router input directory ($POSTOFFICE/router/.)

24.1.16. zmailer cleanup

Run this from your root crontab!

This cleans from $POSTOFFICE/public/ files that are older than 2 days (48 hours), and from $POSTOFFICE/postman/ files with names starting with a digit and aged over 7 days.

24.1.17. zmailer freeze

This sets a flag which is honoured by subsystem start functions:

# /opt/mail/bin/zmailer freeze
freeze 
# /opt/mail/bin/zmailer router
router Sorry, ZMailer is frozen, won't start anything until thawed !
* CHECK THAT THE FREEZE CONDITION ISN'T DUE TO E.G. MAINTENANCE *


24.1.18. zmailer thaw, zmailer unfr(eeze)

Thaws the previously frozen ZMailer system so that zmailer start will be able to start subsystems.

24.2. The newdbprocessor script

FIXME! WRITEME! (See Section E.4.1 for the configuration file)

- Input file syntax
- Supported database types, and what is done to them
- Additional notes ?


24.3. The newdb script

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

newdb [-u | -l] [-a] [-s] [-t dbtype] /db/path/basename [input-file-name]

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

Suffix selection rules are:

dbm     .pag and .dir
ndbm    .pag and .dir
gdbm    .gdbm
btree   .db
bhash   .dbh


24.4. The makedb utility

This utility is used by the ZMailer system to compile source files to various binary databases.

The way the ZMailer uses DBM entries is by using C-strings with their terminating NUL included at keys, and at data.. Thus the length is strlen(string)+1, not strlen(string) !

WARNING: Policy data parsing does use unchecked buffers!

\begin{verbatim}
Usage: makedb [-apsvluA] dbtype database.name [infilename|-]
\end{verbatim}

-a: aliasinput
-p: policyinput
-A: append-mode
-l: pre-lowercasify the key
-u: pre-uppercasify the key
-s: be silent
-v: be verbose

Dbtypes are: {\tt ndbm gdbm btree bhash}

If no {\tt infilename} is defined, {\tt database.name} is assumed.

\begin{description}
\item[{\tt NDBM}] \mbox{}

appends {\tt .pag}, and {\tt .dir}
into the actual db file names.

\item[{\tt GDBM}] \mbox{}

{\bf does not} append {\tt .gdbm}
into the actual db file name.

\item[{\tt BTREE}] \mbox{}

{\bf does not} append {\tt .db}
into the actual db file name.

\item[{\tt BHASH}] \mbox{}

appends {\tt .pag}, and {\tt .dir}
into the actual db file names.

\end{description}


The {\tt -a} option is for parsing input that comes in 
{\tt aliases} format: {\tt key: data,in,single,long,line}

24.5. The dblook utility

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

\begin{verbatim}
Usage: dblook [-dump] dbtype database.name [key]
\end{verbatim}


Dbtypes are: {\tt ndbm gdbm btree bhash}

\begin{description}
\item[{\tt NDBM}] \mbox{}

appends {\tt .pag}, and {\tt .dir} 
into the actual db file names.

\item[{\tt GDBM}] \mbox{}

{\bf does not} append {\tt .gdbm} 
into the actual db file name.

\item[{\tt BTREE}] \mbox{}

{\bf does not} append {\tt .db} 
into the actual db file name.

\item[{\tt BHASH}] \mbox{}

appends {\tt .pag}, and {\tt .dir} 
into the actual db file names.

\end{description}

%\end{multicols}


% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\clearpage

24.6. The policy-builder.sh script

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

#FLAG=
#while getopts n c; do
#  case $c in
#    n)       FLAG=$c;;
#    ?)       exit 2;;
#  esac
#done
#shift `expr $OPTIND - 1`

ZCONFIG=@ZMAILERCFGFILE@
. $ZCONFIG

DBDIR="$MAILVAR/db/"
USAGE="Usage: $0 [-n] [-d dbdir]"

while [ "$1" != "" ]; do
    case "$1" in
        -n)
            FLAG=n
            ;;
        -d)
            shift
            DBDIR=$1
            if [ ! -d $DBDIR ]; then
                echo $USAGE
                exit 1
            fi
            ;;
        ?)
            echo $USAGE
            exit 0
            ;;
        *)
            echo $USAGE
            exit 2
            ;;
    esac
    shift
done


umask 022

cd $DBDIR

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

# -- Former '-f' flag data (non)retrieval section removed

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

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

  # smtp-policy.relay
  # (Lists NETWORKS (NO DOMAINS!) that are allowed to use us as relay)
  # (well, actually it could also list e.g.: ".our.domain" if it would
  #  be fine to allow relaying from anybody whose IP address reverses to
  #  domain suffix ".our.domain")
  if [ -f smtp-policy.relay.manual ] ; then
    echo "# -------------------------"
    echo "# smtp-policy.relay.manual:"
    cat smtp-policy.relay.manual | \
    awk '/^#/{next;}
        {printf "%s = _full_rights\n",$0;next;}'
  fi
  if [ -f smtp-policy.relay ] ; then
    echo "# ------------------"
    echo "# smtp-policy.relay:"
    cat smtp-policy.relay | \
    awk '/^#/{next;}
        {printf "%s = _full_rights\n",$0;next;}'
  fi

  # smtp-policy.mx.manual
  # (Lists domains that are allowed to use us as inbound MX relay for them)
  if [ -f smtp-policy.mx.manual ] ; then
    echo "# ----------------------"
    echo "# smtp-policy.mx.manual:"
    cat smtp-policy.mx.manual | \
    awk '/^#/{next;} NF >= 1 {printf "%s = _relaytarget\n",$0;}'
  fi
  # smtp-policy.mx
  # (Lists domains that are allowed to use us as inbound MX relay for them)
  if [ -f smtp-policy.mx ] ; then
    echo "# ---------------"
    echo "# smtp-policy.mx:"
    cat smtp-policy.mx | \
    awk '/^#/{next;} NF >= 1 {printf "%s = _relaytarget\n",$0;}'
  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 -o -f smtp-policy.spam.manual ] ; then
    echo "# ---------------------------"
    echo "# smtp-policy.spam{,.manual}:"
    ( if [ -f smtp-policy.spam ] ; then
        cat smtp-policy.spam
      fi
      if [ -f smtp-policy.spam.manual ] ; then
        cat smtp-policy.spam.manual
      fi ) | tr "[A-Z]" "[a-z]" | sed 's/^@//g' | sort | uniq | \
    awk '/^\[/{ # an address block to reject
            printf "%s  rejectnet +\n",$0;
            next;
        }
        NF > 0 { # All other cases are usernames with their domains
            printf "%s  = _bulk_mail\n",$0;
        }'
  fi

# --------- end of subshell
) > smtp-policy.dat

umask 022 # Make sure the resulting db file(s) are readable by all

# Build the actual binary policy database (-p), and if the input
# has same key repeating, append latter data instances to the first
# one (-A):

$MAILBIN/makedb -A -p $DBTYPE smtp-policy-new smtp-policy.dat || exit $?

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

24.7. autoanswer

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

  autoanswer:  "| /path/to/MAILBIN/autoanswer"


It yields a reply message for all, except the error messages, nor to those with X-autoanswer-loop: 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.

#!@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 want 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") && ( $double == 1)) {
    last;
    }

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

    $double = 0;

    push(@header,$text);
}

if (($address eq '<>') || $nosend ) {
    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;
}

24.8. vacation

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

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

Usage:

To start vacation, run the command vacation start. It will create a ~/.vacation.msg 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 ~/.forward file in your home directory containing a line of the form:

  "\name", "|/opt/mail/bin/vacation name"
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. Like this:
  chmod og-w $HOME $HOME/.forward
)

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

vacation 'start'
vacation 'stop'
vacation -I
vacation [-tN] [-mMsgfile] [-d] [user]

Parameters:
-I, -i

initialize the .vacation.pag, and .vacation.dir files (or whatever the system supported database is), and start vacation.

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

-tN

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

-mMsgFile

specifies the file in which the message to be sent is kept. The default is $HOME/.vacation.msg.

-r

interval defines interval in days when not to answer again to the same sender. (Default is 1 day.)

-d

disables the list of senders kept in the .vacation.pag and .vacation.dir files. (Or whatever database format is being used.)

Example:
  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

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 “To:” or “Cc:” 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 ~/.vacation.pag and ~/.vacation.dir 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 ~/.vacation.msg and the automatic reply is activated by the ~/.forward (and saved in ~/.vacforward) The default vacation message is stored in $MAILSHARE/vacation.msg

On machines running ZMailer, the “name” argument to vacation is optional, and the $USER environment variable is used to determine where to look for the message and the list of previous recipients.

The $SENDER variable is checked first to determine the reply destination. It is normally set to the SMTP “MAIL FROM:” 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 “From ” line is used only as a last resort.

Notes

[1]

The maximum number of supported TA's is actually probed by the scheduler at its startup; procedure is:

  1. Ask system for maximum number of file descriptors the scheduler's child can have.

  2. Substract “30” from resulting count.

  3. If child communication channel needs two file descriptors (no full-duplex pipe, e.g. socketpair() available), divide the leftover count by two.

  4. Result is the maximum number of TAs which document elsewere refers as “1000”.