<CHAPTER ID="ZREF-UTILITIES"><?dbhtml filename="zref-utilities.html">
<TITLE>ZMailer Utilities Reference</TITLE>

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


<SECT1 ID="zref.util.zmailer">
<TITLE><COMMAND>zmailer</> command script</TITLE>

<PARA>
FIXME! FIXME! TO BE WRITTEN!
subsections for each function ??
</PARA>

</SECT1>

<SECT1 ID="zref.util.vacation">
<TITLE><COMMAND>vacation</></TITLE>

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

<PARA>
This file should include a header with at least
a <QUOTE><LINK LINKEND="rfc822.subject">Subject:</></> line
(it should not include a <QUOTE><LINK LINKEND="rfc822.to">To:</></> line
&mdash; if you want, you may include
<QUOTE><LINK LINKEND="rfc822.from">From:</></> line,
especially if you use the <OPTION>-m</> option), for example.
</PARA>

<VARIABLELIST>
<VARLISTENTRY><TERM>Usage:</><LISTITEM>

<PARA>
To start <COMMAND>vacation</>, run the command <USERINPUT>vacation start</>.
It will create a <FILENAME>~/.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 <FILENAME>~/.forward</> file in your home 
directory containing a line of the form:
<SYNOPSIS>
  "\name", "|/opt/mail/bin/vacation name"
</SYNOPSIS>

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:
<SYNOPSIS>
  chmod og-w $HOME $HOME/.forward
</SYNOPSIS>)
</PARA>

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

<SYNOPSIS>
vacation start vacation stop vacation -I vacation [ -tN ] [ -mMsgfile ] [ -d ] [user]
</SYNOPSIS>

</LISTITEM></VARLISTENTRY>
<VARLISTENTRY><TERM>Parameters:</TERM><LISTITEM>

<!-- VARIABLELIST -->
<SCREEN>
\item[{\tt -I}, {\tt -i}] \mbox{}

initialize the {\tt .vacation.pag} 
and {\tt .vacation.dir} files and start vacation.

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

\item[{\tt -tN}] \mbox{}

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

\item[{\tt -mMsgfile}] \mbox{}

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

\item[{\tt -r}] \mbox{}

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

\item[{\tt -d}] \mbox{}

disables the list of senders kept in the 
{\tt .vacation.pag} and {\tt .vacation.dir} files.

\end{description}
</SCREEN>

</LISTITEM></VARLISTENTRY>
<VARLISTENTRY><TERM>Example:</TERM><LISTITEM>

<SCREEN>
  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
</SCREEN>

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

<PARA>
A list of senders is kept in the files <FILENAME>~/.vacation.pag</> and 
<FILENAME>~/.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 <FILENAME>~/.vacation.msg</> and the automatic
reply is activated by the <FILENAME>~/.forward</> (and saved in
<FILENAME>~/.vacforward</>)
The default vacation message is stored in <FILENAME>/opt/mail/vacation.msg</>
</PARA>

<PARA>
On machines running ZMailer, the ``name'' argument to <COMMAND>vacation</>
is optional, and the $USER environment variable is used to determine where
to look for the message and the list of previous recipients.
</PARA>

<PARA>
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.
</PARA>
</LISTITEM></VARLISTENTRY>
</VARIABLELIST>
</SECT1>

<SECT1 ID="zref.util.makedb">
<TITLE><COMMAND>makedb</></TITLE>

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

<SCREEN>
WARNING: Policy data parsing does use unchecked buffers!

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


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}
</SCREEN>

</SECT1>

<SECT1 ID="zref.util.dblook">
<TITLE><COMMAND>dblook</></TITLE>

<SCREEN>
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
\subsection{{\tt policy-builder.sh}}

\begin{alltt}
#! /bin/sh
#
# Sample smtp-policy-db builder script.
#
# This merges following files from $MAILVAR/db/ directory:
#       smtp-policy.src
#       localnames              ('= _localnames')
#       smtp-policy.relay       ('= _full_rights')
#       smtp-policy.mx          ('relaytargets +')
#       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`

if [ "x$1" = "x-n" ]; then
    FLAG=n
    shift
fi
if [ "x$1" = "x?" ]; then
    exit 2
fi


ZCONFIG=@ZMAILERCFGFILE@
. $ZCONFIG

umask 022

cd $MAILVAR/db

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

if [ f$FLAG != fn ]; then
    if [ -x $MAILBIN/smtp-policy-retrieve.pl ] ; then
        $MAILBIN/smtp-policy-retrieve.pl
    else
        if [ -x $MAILBIN/spamlist.py ] ; then
            $MAILBIN/spamlist.py > smtp-policy.spam.new && \verb/\/
                mv  smtp-policy.spam.new smtp-policy.spam
        else
            #
            # Following IS NOT SAFE, if either produces errors, those
            # go (usually) to the result file, and in the end the result
            # OVERWRITES the "running"  smtp-policy.spam  file.
            #
            > smtp-policy.spam.new
            lynx -source http://www.webeasy.com:8080/spam/spam_download_table \verb/\/
                >> smtp-policy.spam.new
            lynx -source http://www.sprocket.com/Security/SpamDomains | \verb/\/
                awk '\{print $1\}' >> smtp-policy.spam.new
            cat smtp-policy.spam.new | sed 's/^@//g' | tr "[A-Z]" "[a-z]" | \verb/\/
                    sort | uniq > smtp-policy.spam.new2
            if [ `grep -c cyberpromo smtp-policy.spam.new` -gt "0" ]; then
                mv smtp-policy.spam smtp-policy.spam.old
                mv smtp-policy.spam.new2 smtp-policy.spam
                rm -f smtp-policy.spam.new
            else
                echo "Hmm....something went wrong while updating the spam policy."
                echo "Please try again."
                exit 1
            fi
        fi
    fi
fi

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

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

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

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

  # smtp-policy.spam
  # (Lists users, and domains that are known spam sources)
  # (We use file from "http://www.webeasy.com:8080/spam/spam_download_table"
  #  which is intended for QMAIL, and thus needs to be edited..)
  if [ -f smtp-policy.spam -o -f smtp-policy.spam.manual ] ; then
    ( 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 | \verb/\/
    awk '/^\verb/\/[/\{ # an address block to reject
            printf "%s rejectnet +\verb/\/n", $1;
            next;
        \}
        \{ # All other cases are usernames with their domains
          printf "%s = _bulk_mail\verb/\/n", $1;
        \}'
  fi

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

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

$MAILBIN/makedb -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
\end{alltt}
</SCREEN>

</SECT1>

<SECT1 ID=zref.util.autoanswer>
<TITLE><COMMAND>autoanswer</></TITLE>

<PARA>
The <COMMAND>autoanswer</> program is intended to be placed into
system global aliases database as following entry:
<SCREEN>
  autoanswer:  "| /path/to/MAILBIN/autoanswer"
</SCREEN>
</PARA>

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

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

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

<SCREEN>
#!@PERL@

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

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

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

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

close ZMAILER;

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

while (&lt;STDIN&gt;) {

    $text = $_;

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

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

    $double = 0;

    push(@header,$text);
}

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

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

open(OUT,">$outfile");
select(OUT);
print "channel error\n";
print "to $address\n";
print "env-end\n"; 
print "From: Autoreply service &lt;postmaster&gt;\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;
}
</SCREEN>
</SECT1>

<SECT1 ID="zref.util.newdb">
<TITLE><COMMAND>newdb</></TITLE>

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

<SCREEN>
{\bf Usage}

\begin{verbatim}
newdb /db/path/name [-u|-l] [input-file-name]
\end{verbatim}

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

Suffix selection rules are:

\begin{verbatim}
dbm     .pag and .dir
ndbm    .pag and .dir
gdbm    .gdbm
btree   .db   
\end{verbatim}
</SCREEN>

</SECT1>

</CHAPTER>
