\documentclass[a4paper]{article}
\usepackage{linuxdoc-sgml}
\usepackage{qwertz}
\usepackage{url}
\usepackage[latin1]{inputenc}
\usepackage{t1enc}
\usepackage{babel}
\usepackage{epsfig}
\usepackage{null}
\def\addbibtoc{
\addcontentsline{toc}{section}{\numberline{\mbox{}}\relax\bibname}
}%end-preamble
\title{ IFHP-HOWTO}
\author{Patrick Powell
{\ttfamily \onlynameurl{papowell@astart.com}}}
\date{ 17 May 1999 (For ifhp-3.2.9)}
\abstract{The {\ttfamily ifhp} software is an enhanced, extended, highly configurable,
and portable implementation of a print filter for use with the {\ttfamily ifhp}
Print spooler software.
It supports network, serial, and parallel printers,
does page accounting and job recovery,
and allows an extremely high level of configuration and tuning.
The {\ttfamily ifhp} filter gets its flexibility by using a configuration file
to set its operational characteristics.  The configuration file can contain
multiple separate printer configurations,  and the desired one can be
selected by a simple mechanism.
The filter can support vintage text,  PostScript,
PCL, and PJL printers, and can be configured to handle a wide range of
printer quirks and misimplementations.}


\begin{document}
\maketitle
\tableofcontents

\section{Introduction}

The {\ttfamily ifhp} print filter is the latest in a long evolutionary path
of print filters for the {\ttfamily ifhp} printing system.
It is intended to unify several different methods of controlling
printers,  and provide a common code base for future development.

This document is the complete set of references and
installation guide for the {\ttfamily ifhp} printer.
It covers the compilation and installation,
initial testing,
details of system configuration,
and various configuration options that would be needed by the
system administrator.

The reference for Printer Job Language (PJL) related issues
was the Printer Job Language Technical Reference Manual,
Hewlett Packard, 10th Edition, October 1997,
and the reference for PCL related issues was
the PCL 5 Printer Language Technical Reference Manual,
First Edition, 1992.
These manuals are available through the Hewlett Packard Developers Program.
See
\onlynameurl{http://www.hp.com/go/devexchange}
for information on how to join.

Previous releases of {\ttfamily ifhp} had a large selection of
{\ttfamily README}
files
which are now incorporated into the {\ttfamily ifhp}-HOWTO document.

Current information
about LPRng, {\ttfamily ifhp} and the latest release can be found on the LPRng web page:

\onlynameurl{http://www.astart.com/LPRng.html}

There is also a mailing list at {\ttfamily lprng@iona.com}. To subscribe,
send an email to {\ttfamily lprng-request@iona.com}. The body should contain
only the word `subscribe'. To get off the list later on, repeat the
same procedure, but use the word `unsubscribe'.

Several presentations of LPRng and print spooling software have been made
at the Large Scale Installation Administrator (LISA) conferences and
are in the {\ttfamily ifhp} distribution and available on web sites.
\onlynameurl{{$<$}tt{$>$}ifhp{$<$}/tt{$>$} - An Enhanced Printer Spooler System}
was presented at the LISA95 conference,
and is in the LPRng distribution as LPRng-LISA95.ps.
On a more general topic,
the slides for the LISA97 tutorial on
\onlynameurl{Printers and Network Print Spooling}
are also in the LPRng distribution in the DOC/LISA97 directory.




\subsection{Copyright}

Material included in this document from the {\ttfamily ifhp} distribution
Copyright Patrick Powell 1988-1999, where applicable.

The rights to distribute this document complete or in part are hereby
granted for non-commercial purposes. Partial reproductions must
acknowledge the source.

Permission to distribute this file together with LPRng and `derived
works' (as defined in the LPRng license) is explicitly granted. This
is allowed independent of the license under which the software is
distributed.

Citing the document is allowed as long as the source is acknowledged.


\subsection{Disclaimer}

{\bfseries THE MATERIAL IN THIS HOWTO IS PROVIDED WITHOUT FEE AND AS-IS WITH NO
WARRANTY REGARDING FITNESS OF USE FOR ANY PURPOSE. THE AUTHOR AND ALL
CONTRIBUTORS ARE NOT LIABLE FOR ANY DAMAGES, DIRECT OR INDIRECT,
RESULTING FROM THE USE OF INFORMATION PROVIDED IN THIS DOCUMENT.}


\subsection{Commercial Support}

\onlynameurl{AStArt Technologies}
provides commercial support and enhancements for
LPRng, {\ttfamily ifhp}, and other network software.
AStArt provides network and system consulting services for UNIX and NT
systems, as well as real time and network software.


\subsection{Web Site}

Web Page:

\onlynameurl{http://www.astart.com/lprng.html}
\label{secftp}


\subsection{FTP Sites}

The software may be obtained from \\ 
\onlynameurl{ftp://ftp.astart.com/pub/LPRng/FILTERS}(Main site)\\ 

Mirrors:\\ 
\onlynameurl{ftp://ftp.sage-au.org.au/pub/printing/spooler/lprng} (AU)\\ 
\onlynameurl{ftp://ftp.zod.wau.nl/pub/mirror/plp/LPRng} (AU/NZ)\\ 
\onlynameurl{ftp://gwynne.cs.ualberta.ca/pub/LPRng} (CA)\\ 
\onlynameurl{ftp://ftp.informatik.uni-hamburg.de/pub/os/unix/utils/LPRng} (DE)\\ 
\onlynameurl{ftp://ftp.uni-paderborn.de/pub/unix/printer/plp/LPRng} (DE)\\ 
\onlynameurl{ftp://ftp.iona.ie/pub/plp/LPRng} (IE)\\ 
\onlynameurl{ftp://ftp.chembio.ntnu.no/pub/mirrors/LPRng} (NO)\\ 
\onlynameurl{ftp://ftp.mono.org/pub/LPRng} (UK)\\ 
\onlynameurl{ftp://ftp.cs.columbia.edu/pub/archives/pkg/LPRng} (US)\\ 
\onlynameurl{ftp://ftp.cs.umn.edu/pub/LPRng} (US)\\ 
\onlynameurl{ftp://ftp.iona.com/pub/plp/LPRng} (US)\\ 
\onlynameurl{ftp://uiarchive.uiuc.edu/pub/packages/LPRng} (US)\\ 


\subsection{Mailing List}

To join the LPRng mailing list, please send mail to
\onlynameurl{lprng-request@iona.ie} with the word 'subscribe' in the BODY
\label{faqref}


\subsection{PGP Public Key}

The LPRng and {\ttfamily ifhp} distributions have an MD5 checksum calculated,
which is then signed with a PGP public key.
Here is the key for validating the checksums:
\begin{tscreen}
\begin{verbatim}
Type Bits/KeyID    Date       User ID
pub  1024/00D95C9D 1997/01/31 Patrick A. Powell <papowell@astart.com>
                                                          Patrick A. Powell <papowell@sdsu.edu>

-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: 2.6.3i

mQCNAzLygTQAAAEEANBW5fPYjN3wSAnP9xWOUc3CvsMUxjip0cN2sY5qrdoJyIhn
qbAspBopR+tGQfyp5T7C21yfWRRnfXmoJ3FVtgToAsJUYmzoSFY08eDx+rmSqCLe
rdJjX8aG8jVXpGipEo9U4QsUK+OKzx3/y/OaK4cizoWqKvy1l4lEzDsA2VydAAUT
tCdQYXRyaWNrIEEuIFBvd2VsbCA8cGFwb3dlbGxAYXN0YXJ0LmNvbT6JAJUDBRA0
XonoiUTMOwDZXJ0BAQ2cBAC7zU9Fn3sC3x0USJ+3vjhg/qA+Gjb5Fi1dJd4solc4
vJvtf0UL/1/rGipbR+A0XHpHzJUMP9ZfJzKZjaK/d0ZBNlS3i+JnypypeQiAqo9t
FV0OyUCwDfWybgAORuAa2V6UJnAhvj/7TpxMmCApolaIb4yFyKunHa8aBxN+17Ro
rrQlUGF0cmljayBBLiBQb3dlbGwgPHBhcG93ZWxsQHNkc3UuZWR1PokAlQMFEDLy
gTSJRMw7ANlcnQEBYBYD/0zTeoiDNnI+NjaIei6+6z6oakqO70qFVx0FG3aP3kRH
WlDhdtFaAuaMRh+RItHfFfcHhw5K7jiJdgKiTgGfj5Vt3OdHYkeeh/sddqgf9YnS
tpj0u5NfrotPTUw39n6YTgS5/aW0PQfO9dx7jVUcGeod1TGXTe9mIhDMwDJI4J14
=3Zbp
-----END PGP PUBLIC KEY BLOCK-----
\end{verbatim}
\end{tscreen}



\section{Installation and Express Configuration}

Before you do an installation,
you should read the following instructions.
You will need to:
\begin{enumerate}
\item Use GNU Make.  Don't even think about trying to use another
make unless you are a Wizard.  And even the Wizards would
download the GNU Make.
\item Use an ANSI C compiler.
\item Read the {\ttfamily HOWTO/ifhp-HOWTO.$\{$ps,html,text,...$\}$}
file(s).
You are doing this now, so you are off to a good start.
\item Generate the executables.
\item Install the configuration files.
\item Run some simple standalone tests,
i.e. - without using the print spooler.
\item Modify the configuration files to suit your sites requirements.
\item Install the executables.
\item Modify the printcap files and/or add other information to the printcap files.
\item Try the {\ttfamily ifhp} filter with the working print spooler.
\end{enumerate}


In addition, you might want to get the following software,
which can be used with
{\ttfamily ifhp}.
\begin{description}
\item[a2ps - Ascii Text To PostScript Converter] \mbox{}

\onlynameurl{http://www-inf.enst.fr/\~{}demaille/a2ps/}
This package does a very good job of text to PostScript conversion.

\item[enscript - GNU Enscript] \mbox{}

\onlynameurl{http://www.gnu.org/}
This package is a simpler version of a2ps,
and is faster and smaller.

\item[Unix File Utility - Determines the type of file] \mbox{}

\onlynameurl{ftp://ftp.astron.com/pub/file/} or
\onlynameurl{ftp://ftp.deshaw.com/pub/file/}.

\item[LPRng Print Spooler] \mbox{}

\onlynameurl{http://www.astart.com}

\end{description}



\subsection{Configure and Compilation}

The {\ttfamily ifhp} filter uses the AUTOCONF configuration facilty.
The following set of commands will generate configuration files
and compile and install the software and documentation.

It is highly unlikely that you will encounter problems with compilation.
Usually these are due to type definition conflicts in include files.
If you encounter these,
please report these to the LPRng mailing list.
\begin{tscreen}
\begin{verbatim}
configure
make all
# installs ifhp and textps in /usr/local/lib/filters
# installs ifhp.conf in /etc
#  (if already present, in /etc/ifhp.conf.sample)
make install
\end{verbatim}
\end{tscreen}



\subsection{Printcap Configuration}

The basic LPRng printcap configuration is:
\begin{tscreen}
\# printer setup  \\ 
\#  force clients (lpr, lpq, to use server)  \\ 
lp:lp=lp@serverhost  \\ 
\# server information  \\ 
lp:server  \\ 
~~:sd={\itshape spooldir\/}  \\ 
~~:...  \\ 
~~\\ 
~~\# version 1 - using -T options  \\ 
~~\#path to ifhp filter  \\ 
~~:if=/.../ifhp -T{\bfseries options}  \\ 
~~:of=/.../ifhp -T{\bfseries options}  \\ 
~~\\ 
~~\# version 2 - using ifhp printcap entry  \\ 
~~:ifhp={\bfseries options}  \\ 
~~:if=/.../ifhp  \\ 
~~:of=/.../ifhp  
\end{tscreen}


As shown,
options can be passed on the command line using the
{\ttfamily -Toption,option}
method or put into the
{\ttfamily :ifhp=option,option}
list.

Since commas are used to separate options in the
{\ttfamily -T}
option list,
if you want to specify an option with a list of values
the values need to separated with a semicolon
({\ttfamily ;})
as shown below:
\begin{tscreen}
ifhp -Tconfig=./ifhp.conf;/etc/ifhp.conf;./ifhp.conf
\end{tscreen}


By convention,
the
{\ttfamily ifhp}
filter takes its input from STDIN (file descriptor 0)
and expects to write its output to STDOUT (file descriptor 1),
which is normally connected to a printer.
Error and trace information are written to STDERR (file descriptor 2).

As shipped,
the
{\ttfamily ifhp.conf}
file is configured to support a PJL printer which has
the following configuration.
The configuration flags that support or enable these
features are shown as well.
\begin{enumerate}
\item  PJL support ({\ttfamily pjl}).
\item  PostScript (PS) support ({\ttfamily ps}).
\item  PCL support ({\ttfamily pcl}).
\item  Text files printed as PCL ({\ttfamily text}, {\ttfamily default\_language=pcl}).
\item  Banner printing done by LPRng spooler ({\ttfamily banner@})
\item  Status reported from printer (over bidirectional file descriptor 1)  ({\ttfamily status})
\item  Synchronize at start and end ({\ttfamily sync})
\item  Get pagecount information ({\ttfamily pagecount})
\end{enumerate}


The following printers have specfic configuration sections
which are invoked by using the
{\ttfamily model=name}
option.
The HP DeskJet and DesignJet printers use the same
{\ttfamily hpdj} prefix with the model appended.
See Appendix A in the Printer Job Language Technical Reference Manual
for a detailed explanation of these names.
\begin{tscreen}
\begin{verbatim}
apple     hp4000      hp4          hp4l         hp4lc
hp4m      hp4ml       hp4mp        hp4mplus     hp4mv
hp4p      hp4pj       hp4plus      hp4si        hp4simx
hp4v      hp5         hp5l         hp5m         hp5mp
hp5p      hp5si       hp5simopier  hp5simx      hp6l
hp6mp     hp6p        hpcolorlj5   hpcolorlj5m  hpcolorlj
hpdj1200c hpdj1600c   hpdj2000cp   hpdj200      hpdj220
hpdj230   hpdj2500cp  hpdj250c     hpdj330      hpdj350c
hpdj350c  hpdj430     hpdj450c     hpdj455ca    hpdj600
hpdj650c  hpdj700     hpdj750c     hpdj750cplus hpdj755cm
hpiiisi   hpljpro     hppjxl300    postscript   ps
tek       qms1725
\end{verbatim}
\end{tscreen}


In addition to HP printers,
there is also generic support for PostScript only printers.


\subsection{PS, PCL, PJL Printer with Network Connection}

This is the most common configuration,
and the printcap entry would have the following format:
\begin{tscreen}
\# printer setup  \\ 
\#  force clients (lpr, lpq, to use server)  \\ 
lp:lp=lp@serverhost  \\ 
\# server information  \\ 
lp:server  \\ 
~~:sd={\itshape spooldir\/}  \\ 
~~:...  \\ 
~~\#:lp={\itshape printer ip address or DNS name\/}\%9100 \\ 
~~\# eg - :lp=nwpr\%9100 \\ 
~~\# eg - :lp=10.1.1.1\%9100 \\ 
~~:lp=10.1.1.1\%9100 \\ 
~~\#path to ifhp filter  \\ 
~~:if=/.../ifhp  \\ 
~~:of=/.../ifhp
\end{tscreen}


If you have an HP printer in the above list,
you can use:
\begin{tscreen}
\# printer setup  \\ 
\#  force clients (lpr, lpq, to use server)  \\ 
lp:lp=lp@serverhost  \\ 
\# server information  \\ 
lp:server  \\ 
~~:sd={\itshape spooldir\/}  \\ 
~~:...  \\ 
~~:lp={\itshape printer ip address or DNS name\/}\%9100 \\ 
~~:ifhp=model={\itshape name\/}
~~\#path to ifhp filter  \\ 
~~:if=/.../ifhp  \\ 
~~:of=/.../ifhp  
\end{tscreen}



\subsection{PS, PCL, PJL Printer with Parallel Port Connection}

Since the parallel port is unidirectional,
you cannot get status back,
and need to use the
{\ttfamily status@} option to prevent the
{\ttfamily ifhp} filter from expecting it.
The printcap entry would have the following format:
\begin{tscreen}
\# printer setup  \\ 
\#  force clients (lpr, lpq, to use server)  \\ 
lp:lp=lp@serverhost  \\ 
\# server information  \\ 
lp:server  \\ 
~~:sd={\itshape spooldir\/}  \\ 
~~:...  \\ 
~~\# parallel port \\ 
~~:lp={\itshape /dev/lpt\/} \\ 
~~:ifhp=status@ \\ 
~~\#path to ifhp filter  \\ 
~~:if=/.../ifhp  \\ 
~~:of=/.../ifhp  
\end{tscreen}





\subsection{PS, PCL, PJL Printer with Serial Port}

The LPRng print spooler will open and set the serial
line characteristics,
and pass the open connection to the
{\ttfamily ifhp} filter.
The 
{\ttfamily tty} connection must pass all 8 bits with no parity,
and should use hardware flow control if at all possible.
for your system,
\begin{tscreen}
\# printer setup  \\ 
\#  force clients (lpr, lpq, to use server)  \\ 
lp:lp=lp@serverhost  \\ 
\# server information  \\ 
lp:server  \\ 
~~:sd={\itshape spooldir\/}  \\ 
~~:...  \\ 
~~\# serial port \\ 
~~:lp={\itshape /dev/ttyxxx\/} \\ 
~~:stty=38400 -echo -crmod -raw -oddp -evenp $\backslash$ \\ 
~~   ixon pass8 -ixany cbreak crtscts \\ 
~~\#path to ifhp filter  \\ 
~~:if=/.../ifhp  \\ 
~~:of=/.../ifhp  
\end{tscreen}



\subsection{PostScript Only Printer}

Use the configuration appropriate to the printer connection,
and then use the
{\ttfamily pjl@}, {\ttfamily pcl@}, and {\ttfamily text@}
option to inhibit everything but PostScript.
\begin{tscreen}
\# printer setup  \\ 
\#  force clients (lpr, lpq, to use server)\\ 
lp:lp=lp@serverhost \\ 
\# server information  \\ 
lp:server  \\ 
~~:sd={\itshape spooldir\/} \\ 
~~:...  \\ 
~~:ifhp=pcl@,pjl@,text@ \\ 
~~\#path to ifhp filter  \\ 
~~:if=/.../ifhp  \\ 
~~:of=/.../ifhp  
\end{tscreen}


If you have a parallel port printer with no PostScript support,
you would use:
\begin{tscreen}
:ifhp=pcl@,pjl@,text@
\end{tscreen}


An alternative is to use the
{\ttfamily model=ps}
configuration section of the default
{\ttfamily /etc/ifhp.conf} file.
\begin{tscreen}
\# printer setup  \\ 
\#  force clients (lpr, lpq, to use server)  \\ 
lp:lp=lp@serverhost  \\ 
\# server information  \\ 
lp:server  \\ 
~~:sd={\itshape spooldir\/}  \\ 
~~:...  \\ 
~~:ifhp=model=ps
~~\#path to ifhp filter  \\ 
~~:if=/.../ifhp  \\ 
~~:of=/.../ifhp  
\end{tscreen}


If your printer does not like to have a PostScript EOJ (Control-D)
flag at the start of a job,
use the
{\ttfamily no\_ps\_eoj}
(\ref{no_ps_eoj} {(No PS EOJ at Start)}) flags.
flag to remove them.


\subsection{PostScript Only Printer With Text Conversion}

You can use the PostScript Only configuration above,
and add text to postscript conversion to it.
This is done by defining the pathname to a text to PostScript
conversion program and causing ifhp to use the
program to convert the input file to PostScript.
The
{\itshape a2ps\/}
program can be obtained from
\onlynameurl{http://www-inf.enst.fr/\~{}demaille/a2ps/}
and does an excellent job.
Also,
the
{\ttfamily textps}
program included with this distribution does a (barely) adequate job as well.

The method outlined here assumes that the input file
is a text file and that the {\ttfamily a2ps} program will convert it.
The
{\ttfamily a2ps} program needs to be explicitly told that output
is to go to
{\ttfamily STDOUT} or file descriptor 1.
\begin{tscreen}
\begin{verbatim}
text_converter=/usr/local/bin/a2ps -o-
text_converter_output=ps
tempfile=/var/tmp/ifhp
\end{verbatim}
\end{tscreen}

\begin{tscreen}
\# printer setup  \\ 
\#  force clients (lpr, lpq, to use server)  \\ 
lp:lp=lp@serverhost  \\ 
\# server information  \\ 
lp:server  \\ 
~~:sd={\itshape spooldir\/}  \\ 
~~:...  \\ 
~~:ifhp=pcl@,pjl@,text@,text\_converter=...,$\backslash$ \\ 
~~~~~~~text\_converter\_output=ps~\\ 
~~\#path to ifhp filter  \\ 
~~:if=/.../ifhp  \\ 
~~:of=/.../ifhp  
\end{tscreen}





\subsection{Tektronixs Phaser Series Printer with Network Connections}

The Tektronics Phaser Series printers use the
{\itshape Appsocket\/} protocol when sending a job to the printer.
This protocol is (briefly):
\begin{enumerate}
\item  The printer listens for UDP packets on port 9101
and for TCP/IP connections on port 9100.
\item  When a UDP packet is recieved on port 9101, then a reply
packet containing the status is returned to the originator's
address.
This packet contains an status indication,
in a {\itshape undefined\/} format.
\item  To send a job to the printer,  a TCP/IP connection is opened to port
9100,
and a PostScript job is sent.
Only a single job can be sent at a time - a EOJ (CTRL-D)
will terminate input and flush all following jobs.
\item Return status will be sent in the reverse direction until the job
has completed,
at which point the connection will be closed.
\end{enumerate}


The {\ttfamily ifhp} program supports the {\ttfamily appsocket} protocol.
In order to do so,
the following ifhp configuration entry can be used.
\begin{tscreen}
\begin{verbatim}
[ tek ]
appsocket
pjl@
pcl@
\end{verbatim}
\end{tscreen}

The {\ttfamily appsocket} option will use the appsocket protcol,
and cause {\ttfamily ifhp} to open and close connections to the printer.
The printcap entry should specify
{\ttfamily lp=/dev/null}
and provide the device IP address using the {\ttfamily -Tdev=host\%port} option.
\begin{tscreen}
\# Phaser Setup
lp:server  \\ 
~~:{\itshape lp=/dev/null\/}  \\ 
~~:sd={\itshape spooldir\/}  \\ 
~~:...  \\ 
~~:ifhp=model=tek,dev=10.0.0.1\%9100\\ 
~~\#path to ifhp filter  \\ 
~~:if=/.../ifhp  \\ 
~~:of=/.../ifhp  
\end{tscreen}





\section{Configuration Tutorial}

This section is a basic tutorial on using many of the features of
the
{\ttfamily ifhp}
filter.
If you plan to make use of any of the advanced filter options or
modify the configuration,
you should read and try out several of the
configuration exercises.


\subsection{Configuration Files and Testsupport Directory }

These exercises require the use of several configuration files
that have predefined values as well as the
default
{\ttfamily /etc/ifhp.conf} file.
The test files are normally located in the distribution 
{\ttfamily testscripts}
directory.
It is assumed that these exercises will be done in that
directory.

The
{\ttfamily config=path;path;path}
option specifies the list of configuration files for
{\ttfamily ifhp}
to read.
Here is a sample of the configuration file
{\ttfamily t1.conf}:
\begin{tscreen}
\begin{verbatim}
# modify the next line to contain
#  the name, IP address, or pathname of the printer
dev=CHANGE_THIS
debug=3
stty=38400 -echo -crmod -raw -oddp -evenp ixon pass8 -ixany cbreak crtscts
trace
ps@ 
pjl@
pcl@
text
\end{verbatim}
\end{tscreen}


The command
\begin{tscreen}
ifhp -T/etc/ifhp.conf;t1.conf
\end{tscreen}

will cause the
{\ttfamily /etc/ifhp.conf} and then the
{\ttfamily t1.conf} file to be read and configuration information extracted.

The various options in this file are quite important for debugging
and testing.
The
{\ttfamily debug}
and
{\ttfamily trace}
options can also be specifed on the command line,
and cause the debug facilities to be turned on and debug trace output
to be put to
{\ttfamily STDERR}.
Normally,
trace output is written only to the
{\ttfamily statusfile}
specified by the command line
{\ttfamily -s} option or the configuration file
{\ttfamily statusfile=path} entry.

The
{\ttfamily text} entry causes the filter to accept text files
and simply pass them through without processing,
and the
{\ttfamily ps@}
{\ttfamily pjl@}
{\ttfamily pcl@}
entries disable related processing.


\subsection{Output Device Specification}

In normal operation,
{\ttfamily ifhp}
sends its output to
{\ttfamily STDOUT} or file desciptor 2.
However,
when testing or using the
{\ttfamily ifhp}
filter in standalone mode,
it is useful to have the filter open the connection
to a file or device directly.
The following sections
discuss how to modify the configuration file to do this,
as well as how to implement a simple
a


\subsection{Output to a File}

This method is useful when trying to debug a set of configuration
options and you want to capture output to a file.
The
{\ttfamily dev=path}
option is used to specify the output pathname.
\begin{enumerate}
\item In the
{\ttfamily testscripts}
directory,
copy the
{\ttfamily t1.conf}
file to
{\ttfamily ifhp.conf}
and edit 
{\ttfamily ifhp.conf}
so it has the following lines:
\begin{tscreen}
\begin{verbatim}
# dev=/tmp/out
# debug=3
stty=38400 -echo -crmod -raw -oddp -evenp ixon pass8 -ixany cbreak crtscts
trace
ps@ 
pjl@
pcl@
text
\end{verbatim}
\end{tscreen}
\item Run the indicated commands and you should see similar output:
\begin{tscreen}
\begin{verbatim}
##> ifhp -Tconfig=./ifhp.conf < hi.txt
ifhp 12:28:20.603 [6089] Process_job: setting up printer
ifhp 12:28:20.605 [6089] Do_accounting: accounting at start, pagecount 0, pages 0
ifhp 12:28:20.605 [6089] Process_job: sending job file
ifhp 12:28:20.605 [6089] Send_job: starting transfer
Hello World

ifhp 12:28:20.606 [6089] Send_job: finished writing file, cleaning up
ifhp 12:28:20.606 [6089] Process_job: sent job file
ifhp 12:28:20.606 [6089] Process_job: doing cleanup
ifhp 12:28:20.606 [6089] Do_accounting: accounting at end, pagecount 0, pages 0
ifhp 12:28:20.606 [6089] Process_job: done
\end{verbatim}
\end{tscreen}
\item Now modify the
{\ttfamily ifhp.conf} file to look like:
\begin{tscreen}
\begin{verbatim}
dev=/tmp/out
debug=3
trace
ps@ 
pjl@
pcl@
text
\end{verbatim}
\end{tscreen}
\item Run indicated commands and you should see similar output:
\begin{tscreen}
\begin{verbatim}
##> ifhp -Tconfig=./ifhp.conf < hi.txt
ifhp 12:33:39.504 [6155] Open_device: device '/tmp/out'
ifhp 12:33:39.505 [6155] Open_device: device '/tmp/out', attempt 1
ifhp 12:33:39.506 [6155] Open_device: success
ifhp 12:33:39.506 [6155] main: fd 1 device 0100000
 ...
\end{verbatim}
\end{tscreen}
\item Clearly this is very verbose diagnostic or trace output.  However,
if you use
{\ttfamily cat /tmp/out}
you will see the output has been written correctly.
Try using the following command to redirect trace and error output
to a file for later examination.
\begin{tscreen}
\begin{verbatim}
CSH                     SH
ifhp ... <in >&out      ifhp ... <in 2>out
\end{verbatim}
\end{tscreen}
\end{enumerate}



\subsection{Default ifhp.conf File and Simple CRLF Filter}

In order to simplify operation,
if there is a
{\ttfamily ifhp.conf} file in the current directory,
then the
{\ttfamily ifhp} program will read this file first,
followed by
{\ttfamily /etc/ifhp.conf}
and then rereads the
{\ttfamily ifhp.conf}
This has the effect of extracting critical option information on the
first pass through
{\ttfamily ifhp.conf},
then reading the default information from
{\ttfamily /etc/ifhp.conf},
and finally re-reading
{\ttfamily ifhp.conf} to override any defaults. 
\begin{enumerate}
\item Try the simple commands
\begin{tscreen}
\begin{verbatim}
echo >/tmp/out
ifhp <hi.txt
\end{verbatim}
\end{tscreen}

and note that it produces the same output as befoe.
\item Now modify the
{\ttfamily ifhp.conf} file to contain:
\begin{tscreen}
\begin{verbatim}
dev=/tmp/out
debug=3
trace
ps@ 
pjl@
pcl@
text
crlf
\end{verbatim}
\end{tscreen}

and do
\begin{tscreen}
ifhp $<$hi.txt
\end{tscreen}

again, without clearing the output file.
\item If you examine 
{\ttfamily /tmp/out}output using the 
{\ttfamily od} or {\ttfamily hexdump} file dump programs or the
{\ttfamily vi} text editor,
you will find that the LF
({\ttfamily $\backslash$n}) character has been replaced by
CR LF ({\ttfamily $\backslash$r$\backslash$n}).
\item You can use the
{\ttfamily ifhp}
program as a simple CRLF filter by specifying:
\begin{tscreen}
ifhp -Tcrlf,language=unknown $<$hi.txt
\end{tscreen}

The
{\ttfamily language=unknown} option specifies that the ifhp
program is not to guess at the language type,
and then does CRLF translation.

\end{enumerate}



\subsection{HP Jetdirect or Compatible Network Interface}

If a printer has HP Jetdirect compatibility,
then the printers TCP/IP port 9100 will accept jobs
for printing and provide printer status.

Other manufacturers make similar products,
and may support equivalent functionality on different ports.
If you are using a Network Printer Box with multiple printer ports,
then each printer port is accessible using a specific TCP/IP port.
For example,
parallel ports P1, P2, and P3 and on a JetDirect box are usually accessed
using TCP/IP ports 9100, 9101, and 9102 respectively.

If you are using a Network Printer Box and are connecting to a
parallel port printer,
then you may not get status or error messages back from the printer
unless both the printer and the Network Printer Box use bi-directional
communication.

In the following discussions,
we will assume that you have assigned an IP address to the printer,
and that it is {\ttfamily nwpr},
and that status and error information is returned over the network
connection.
\begin{enumerate}
\item First,
verify that your printer is accessible on the network by using
{\ttfamily ping}.
It is amazing how many problems are caused by erroneous
network addresses.
\begin{tscreen}
astart: \% ping nwpr \\ 
PING nwpr.astart.com (10.0.0.10): 56 data bytes \\ 
64 bytes from 10.0.0.10: icmp\_seq=0 ttl=60 time=4.286 ms 
\end{tscreen}
\item Now use
{\ttfamily telnet}
to check that you can connect to port 9100.
\begin{tscreen}
\begin{verbatim}
astart: % telnet nwpr 9100
Trying 206.71.174.206...
Connected to nwpr.astart.com.
Escape character is '^]'.
...
\end{verbatim}
\end{tscreen}
\item If you have a PostScript printer,
then you might want to play with the PostScript Interactive mode,
described in
Appendix D.5 of the PostScript Language Reference Manual
by Adobe Systems.
Simply type the command
\begin{tscreen}
executive
\end{tscreen}

as the first characters that are sent.
You should see:
\begin{tscreen}
\begin{verbatim}
>># telnet nwpr
Connected to nwpr.astart.com.
Escape character is '^]'.
executive
PostScript(r) Version 2013.111
(c) Copyright 1984-1993 Adobe Systems Incorporated.
Typefaces (c) Copyright 1981 Linotype-Hell AG and/or its subsidiaries.
All Rights Reserved.
PS>
\end{verbatim}
\end{tscreen}
\item You may want to try sending a simple file to the printer
and examining what happens.
This is easily done using the
{\ttfamily netcat}
program  by Mudge.
See
\onlynameurl{http://www.l0pht.com/\~{}weld/netcat/index.html}
for general information.
\item The
{\ttfamily hi.txt}
file contains
\begin{tscreen}
Hello World \\ 
\^{}L 
\end{tscreen}

where {\ttfamily \^{}L} is the form feed character
You can send this file to the printer using:
\begin{tscreen}
nc printer 9100 $<$hi.txt
\end{tscreen}

The printer should start up and print a single page of output.
You may need to use
{\ttfamily CTRL-C} to 
terminate the
{\ttfamily nc}
program.

\item If you have a PostScript printer,
you might try sending a simple PostScript test program to the printer
as well.
The
{\ttfamily ellipse.ps}
file can be sent using:
\begin{tscreen}
nc printer 9100 $<$/tmp/hi1.txt
\end{tscreen}
\item You can now test the basic
{\ttfamily ifhp}
functionality.
\item Copy the
{\ttfamily t1.conf}
file to
{\ttfamily ifhp.conf}
and edit is so it has the correct network printer information.
\begin{tscreen}
\# modify the next line to contain \\ 
\#  the name, IP address, or pathname of the printer
dev={\itshape nwpr\/}\%9100 \\ 
debug=3 \\ 
trace\_to\_stderr \\ 
ps@
pjl@
pcl@
text 
\end{tscreen}
\item Now do the indicated command; you should get similar output
\begin{tscreen}
\begin{verbatim}
astart: % ifhp <hi.txt
\end{verbatim}
\end{tscreen}

Note the extreme verbosity of output.
\item At this point you might want to try getting page numbers and doing
synchronization.
If you have a HP printer that supports PJL,
then modify
{\ttfamily t2hp.conf} as above.
This file has the contents:
\begin{tscreen}
\begin{verbatim}
# modify the next line to contain <newline>
#  the name, IP address, or pathname of the printer
dev=<it/nwpr/%9100 <newline>
#debug=3 <newline>
trace_to_stderr <newline>
text <newline>
pjl <newline>
sync=pjl <newline>
pagecount=pjl <newline>
\end{verbatim}
\end{tscreen}

Now use the following command and you should see similar output.
\begin{tscreen}
\begin{verbatim}
ifhp '-Tconfig=t2hp.conf;/etc/ifhp.conf;t2hp.conf' < hi1.txt
ifhp 16:44:16.541 [3199] Process_job: setting up printer
ifhp 16:44:16.545 [3199] Do_sync: starting sync using 'pjl'
ifhp 16:44:17.935 [3199] Check_device_status: device = 'Toner Low'
ifhp 16:44:18.116 [3199] Do_sync: sync done
ifhp 16:44:18.117 [3199] Do_pagecount: getting pagecount using 'pjl'
ifhp 16:44:20.011 [3199] Do_pagecount: final pagecount 63304
ifhp 16:44:20.013 [3199] Do_accounting: accounting at start, pagecount 63304, pages 0
ifhp 16:44:20.013 [3199] Process_job: sending job file
ifhp 16:44:20.014 [3199] Send_job: starting transfer
ifhp 16:44:20.115 [3199] Use_file_util: file identified as 'ascii text ', assigned type 'text'
ifhp 16:44:20.119 [3199] Send_job: finished writing file, cleaning up
ifhp 16:44:20.119 [3199] Process_job: sent job file
ifhp 16:44:20.119 [3199] Process_job: doing cleanup
ifhp 16:44:20.120 [3199] Do_sync: starting sync using 'pjl'
ifhp 16:44:22.175 [3199] Do_sync: sync done
ifhp 16:44:22.176 [3199] Do_waitend: getting end using 'pjl'
ifhp 16:44:22.529 [3199] Check_device_status: device = 'Warming Up'
ifhp 16:45:04.669 [3199] Check_device_status: device = 'Toner Low'
ifhp 16:45:21.361 [3199] Do_pagecount: getting pagecount using 'pjl'
ifhp 16:45:23.241 [3199] Do_pagecount: final pagecount 63305
ifhp 16:45:23.243 [3199] Do_accounting: accounting at end, pagecount 63305, pages 1
ifhp 16:45:23.243 [3199] Process_job: done
\end{verbatim}
\end{tscreen}
\item At this point,
you should be able to send jobs to the printer,
and now need to put these options into the printcap file.
Please see the section on
\ref{finetune} {(Printcaps and Fine Tuning Configurations)}
\end{enumerate}



\subsection{Serial Port}

If your printer is attached using a serial port,
then you must make sure that the communication channel is
configured correctly.
The
{\ttfamily dev=/dev/ttyxxx}
and
{\ttfamily stty=...}
configuration options will open the serial port
and configure the line in an appropriate manner.
For details on the exact form of the
{\ttfamily stty} options,
please consult the
LPRng-HOWTO documentation.
\begin{enumerate}
\item Copy the
{\ttfamily t1.conf}
file to
{\ttfamily ifhp.conf} and edit it
so it has the following lines:
\begin{tscreen}
\# modify the next line to contain \\ 
\#  the name, IP address, or pathname of the printer
dev={\itshape /dev/serialport \/}\\ 
\#debug=3 \\ 
stty=38400 -echo -crmod -raw -oddp -evenp ixon
pass8 -ixany cbreak crtscts
trace\_to\_stderr \\ 
text 
\end{tscreen}

Now run the
{\ttfamily ifhp}
program as shown below.
You should see output similar to:
\begin{tscreen}
\begin{verbatim}
astart: % ifhp <h11.txt
ifhp 15:57:23.734 [3096] Process_job: setting up printer
ifhp 15:57:23.736 [3096] Do_accounting: accounting at start, pagecount 0, pages 0
ifhp 15:57:23.736 [3096] Process_job: sending job file
ifhp 15:57:23.736 [3096] Send_job: starting transfer
ifhp 15:57:23.737 [3096] Send_job: finished writing file, cleaning up
ifhp 15:57:23.737 [3096] Process_job: sent job file
ifhp 15:57:23.738 [3096] Process_job: doing cleanup
ifhp 15:57:23.738 [3096] Do_accounting: accounting at end, pagecount 0, pages 0
ifhp 15:57:23.738 [3096] Process_job: done
\end{verbatim}
\end{tscreen}

and you should get a printed page.

\item If you do not get communication,
then you will have to start a long and painful process of debugging.
First,
check that the various modem control signals
are correct.
You should invest a small amount of time and energy and purchase
a
{\bfseries breakout box} that shows the status of the various control signals.
If only the
{\bfseries XMIT Data} signal is active,
you will need to put a crossover (null modem)
between the printer and your serial port.
Check the
{\bfseries DTR} (Data Terminal Ready),
{\bfseries DCD} (Data Carrier Detect),
{\bfseries RTS} (Request To Send),
and
{\bfseries CTS} (Clear To Send).
These should all be ON or active.
Some systems will use
{\bfseries RTS} (Request To Send)
and
{\bfseries CTS} (Clear To Send) for
{\itshape hardware flow control\/}
and it is possible that these signals will become stuck.
It is strongly recommended that flow control on the host be turned off,
and let the printer do flow control using 
{\bfseries RTS} and
{\bfseries CTS}.

\item Once you get the basic configuration working,
then you should follow the basic steps in the
previous section on Network Interfaces,
and try sending files of different types.
\end{enumerate}



\subsection{Parallel Port}

The parallel port configuration is the easiest to implement,
but the most limited in abilities.
\begin{enumerate}
\item Copy the
{\ttfamily t1.conf}
file to
{\ttfamily ifhp.conf} and edit it
so it has the following lines, with the
{\ttfamily dev} value replaced by the correct pathname.
\begin{tscreen}
\# modify the next line to contain \\ 
\#  the name, IP address, or pathname of the printer \\ 
dev={\itshape /dev/lp\/} \\ 
debug=3 \\ 
stty=38400 -echo -crmod -raw -oddp -evenp ixon pass8 -ixany cbreak crtscts \\ 
trace \\ 
ps@ \\ 
pjl@ \\ 
pcl@ \\ 
text \\ 
\end{tscreen}
\item Now run the
{\ttfamily ifhp}
program:
\begin{tscreen}
ifhp $<$hi.txt
\end{tscreen}
\item You should see output similar to:
\begin{tscreen}
\begin{verbatim}
astart: % ifhp -Tconfig=.../testscripts/t1.conf <h11.txt
ifhp 15:57:23.734 [3096] Process_job: setting up printer
ifhp 15:57:23.736 [3096] Do_accounting: accounting at start, pagecount 0, pages 0
ifhp 15:57:23.736 [3096] Process_job: sending job file
ifhp 15:57:23.736 [3096] Send_job: starting transfer
ifhp 15:57:23.737 [3096] Send_job: finished writing file, cleaning up
ifhp 15:57:23.737 [3096] Process_job: sent job file
ifhp 15:57:23.738 [3096] Process_job: doing cleanup
ifhp 15:57:23.738 [3096] Do_accounting: accounting at end, pagecount 0, pages 0
ifhp 15:57:23.738 [3096] Process_job: done
\end{verbatim}
\end{tscreen}

and you should get a printed page.
If you happen to have an operating system that support bi-directional
parallel ports, you can add to the ifhp
\begin{tscreen}
read\_write
\end{tscreen}

which will cause ifhp to open the port read/write.



\end{enumerate}



\subsection{Fine Tuning A Configuration and Printcap Entries
\label{finetune}}

If you have followed the above directions,
you should now be able to use the IFHP filter with
very little additional configuration.
You can now set up your printcap to use the
{\ttfamily ifhp} filter.
The following discussion assumes that you are using LPRng.


\subsection{ifhp.conf Defaults}

While the above set of exercises are useful for debugging
and testing,
you should always let the LPRng spooler open the printing device
or make the network connection.

Examine the
{\ttfamily /etc/ifhp.conf}
file.
The default configuration is for a HP family printer
which supports pagecounting using PJL,
synchronization using PJL,
and other standard items.

If the default configuration does not meet your needs,
and you do not want to use the printcap
{\ttfamily :ifhp}
entry
or pass options using the
{\ttfamily -T}
command line entries,
you can create your own entry in a
{\ttfamily /... spooldir .../ifhp.conf}
file.
This entry should have the form:
\begin{tscreen}
\begin{verbatim}
option
 ...
\end{verbatim}
\end{tscreen}


For example,
we might want to configure a printer that supports PCL and PostScript,
needs to convert Text to PostScript,
and does not have status capability.
This is similar to an HP3 with a PostScript cartridge on a parallel port.
\begin{tscreen}
\begin{verbatim}
status@
pjl@
pcl
ps
text@
text_converter=/usr/local/bin/a2ps -o-
text_converter_output=ps
\end{verbatim}
\end{tscreen}


An alternative to this method is to create a new entry in the
{\ttfamily /etc/ifhp.conf}
file and reference this.
This method has the benefit of centralizing management of the
printing configuration.
You usually put such an entry at the end of the
{\ttfamily /etc/ifhp.conf}
file,
and it would have the form:
\begin{tscreen}
\begin{verbatim}
[ hp3_parallel ]
status@
pjl@
pcl
ps
text@
text_converter=/usr/local/bin/a2ps -o-
text_converter_output=ps
\end{verbatim}
\end{tscreen}


You would modify the printcap so that the model was passed
either in the
{\ttfamily :ifhp} information or as a command line option:
\begin{tscreen}
\begin{verbatim}
printer:...<newline>
  :if=/.../ifhp -Tmodel=hp3_parallel<newline>
  :of=/.../ifhp -Tmodel=hp3_parallel<newline>
  # or you can use this
  :ifhp=model=hp3_parallel
\end{verbatim}
\end{tscreen}



\subsection{Extending ifhp Capabilties
\label{ps_user_opts}
\label{pcl_user_opts}}

One problem faced by system administrators
is the need to allow users to configure various options in a job
specific manner.
In order to support this,
the LPRng print spooler passes the
{\ttfamily lpr -Z}
command line options through to the print spooler,
where they are used by the
{\ttfamily ifhp}
filter.

The details of how these options are used are explained in detail
in the following sections,
but here is an overview of how commands can be added.

The
{\ttfamily pjl\_user\_opts=[ ... ]},
{\ttfamily pcl\_user\_opts=[ ... ]},
and
{\ttfamily ps\_user\_opts=[ ... ]}
are options with predefined meanings.
The values of these options specify
{\ttfamily -Z}
and
{\ttfamily -T}
command line options that will be processed by the
{\ttfamily ifhp}
filter when
{\ttfamily pjl}, {\ttfamily pcl}, or {\ttfamily ps} configuration needs to be done.
Here is a sample configuration file section,
and an example.
\begin{tscreen}
\begin{verbatim}
# we add the upper and lower keywords
#  lpr -Zupper  or lpr -Zlower will be specified by the user
pjl_user_opts=[ upper lower ]
pjl_upper=@PJL SET INTRAY=TRAY1
pjl_lower=@PJL SET INTRAY=TRAY2

#  lpr -Zpagesetup
pcl_user_opts=[ pagesetup ]
pcl_pagesetup=[ lines=12 cols=4 ]
lines=20
pcl_lines=\033*(\%{lines}L
cols=2
pcl_cols=\033*(\%{cols}C
\end{verbatim}
\end{tscreen}


If the user specifies
{\ttfamily lpr -Zupper},
if
{\ttfamily PJL}
is available on the printer
({\ttfamily pjl} is set),
then the
{\ttfamily -Z}
option list is scanned for an option that is also in the
{\ttfamily pjl\_user\_opts}.
The
{\ttfamily upper}
option is found,
and then the value for
{\ttfamily pjl\_upper}
is located and sent to the printer.
By prefixing the context or language that is needed,
we can have multiple language dependent actions for the same option.

The
{\ttfamily lpr -Zpagesetup}
option is more complex,
mainly due to the range of possibilities the PCL offers.
The
{\ttfamily pagesetup}
option is found in the
{\ttfamily pcl\_user\_opts} list,
but when
{\ttfamily pcl\_pagesetup}
is found,
it turns out to be a list of values.

The list values are expanded in turn,
resulting in
{\ttfamily pcl\_lines}
and
{\ttfamily pcl\_cols}
being expanded in turn.
The {\ttfamily pcl\_lines=$\backslash$033*($\backslash$\%$\{$lines$\}$L}
uses the common C/C++/Perl escape sequences,
with the following addition:
{\ttfamily $\backslash$\%$\{$name$\}$}
is replaced by the value for the option name found by searching
in order a
a stack of values that have been set by the recursive expansion,
the
{\ttfamily -Z} options,
{\ttfamily -T} options, 
and the configuration file.
In this example,
we would produce the output string
\begin{tscreen}
\begin{verbatim}
\033*(12L\033*(4C
\end{verbatim}
\end{tscreen}


For examples of how to add these commands,
please examine the default
{\ttfamily /etc/ifhp.conf}.


\subsection{PCL and PostScript End of Job Sequences
\label{no_ps_eoj}
\label{no_pcl_eoj}}

One of the more troublesome problems with printing PCL and PostScript
jobs is to initialize the printer when a previous job has failed.
This is commonly done by prefixing a job file with a
{\itshape end of job\/}
sequence for the particular language.
For PostScript,
this the the Control-D ({\ttfamily $\backslash$004}) character,
and for PCL the ESCAPE E ({\ttfamily $\backslash$033E}) sequence.

One problem with using this approach is that when you want to prefix a job
with additional PCL or PostScript,
you need to remove the existing end of job sequences,
or the prefixed commands will have no effect.
By default,
the {\ttfamily ifhp}
filter will do this.
In addition,
it will also
prefix the new commands with
an appropriate end of job sequence.

However,
there are certain models of printers which do not like to have
end of job sequences at the start of jobs.
To suppress the prefixing of PostScript jobs with the PostScript end of job,
set the
{\ttfamily no\_ps\_eoj}
flag,
and 
to suppress the prefixing of PCL jobs with the PCL end of job,
set the
{\ttfamily no\_pcl\_eoj}
flag.


\section{Filter Operation Details}

\label{read_write}
The
{\ttfamily ifhp}
filter operates by first reading a configuration file
to determine the type of printer it is working with,
and then proceeds to carry out operations requested by the values of
option variables passed on the command line or found in the configuration
files.
In normal operation,
input is read from 
{\ttfamily STDIN}
(file descriptor 0),
massaged in the appropriate manner,
and then written out to
{\ttfamily STDOUT} (file descriptor 1).
Status reports are written to
a status file, or optionally to
{\ttfamily STDERR} (file descriptor 2),
together with any error messages or diagnostics.

In addition to normal operation
the filter can run in the
{\bfseries OF} mode and act as a printer initializer and job terminator.
This is discussed in detail in the LPRng documentation.
When in the OF mode,
The first nonblank input line will be treated as
a request to generate a banner.
The string "$\backslash$031$\backslash$001" will cause the filter to suspend operations
using a SIGSUSP signal.
At this point,
job files will be sent to the output device by the spooler,
and the filter will then be restarted with a SIGCONT signal.

These steps are best explained algorithmically.
The following is a {\itshape pseudo-code\/} description of the steps
performed during the printing activity.
The sections marked with {\ttfamily \#\#\#} are discussed later in this document
in detail.

{\ttfamily ///} See: \ref{setup} {(Options, Initialization and Setup)}
\begin{tscreen}
\begin{verbatim}
###+++ Initialization and Setup
// get ifhp information from PRINTCAP_ENTRY environment variable
if( PRINTCAP_ENTRY environment variable has a value ){
        split printcap information into printcap fields
        if( :ifhp=options,options is present in printcap ){
                split the options list and place in the Toptions list
        }
}
foreach option in -Toptions, -Zoptions do
    if( option = "debug=level"  and Debuglevel not set ){
        set Debuglevel = level;
    }
    if( option = "trace" ){
        output error and trace on STDERR
    }
    if( option = "config=pathlist" and from -Toption ){
        set configuration pathlist = pathlist;
    }
    if( option = "model=name" and model not set ){
        set model = name;
    }
}
\end{verbatim}
\end{tscreen}

{\ttfamily ///} See: \ref{optioninit} {(Operation Configuration Options)}
\begin{tscreen}
\begin{verbatim}
// extract configuration information
foreach path in configuration pathlist {
    open path;
    for each line in file information {
                if( line is selected to be in configuration ){
                        process input line, adding it to configuration
                        if( line is 'debug=','model='
                           and the corresponding value not set ){
                           set the value;
                        }
                }
    }
}

// get values of options with predefined meanings
// these include status, forcestatus, etc
foreach option in predefined list {
        if( option=value is in selected configuration information ){
                set option=value;
        }
}

// open a direct connection if specified
if( device specified using -Tdev=device ){
        // if device is host%port, we open TCP/IP connection
        fd = open(device);
        // Note - option read_write will open the device or file read write
        dup fd to 1; close fd;
}
if( appsocket procotol specified and TCP/IP device ){
        udp_socket = open( udp socket to device%port+1 )
}


###---
\end{verbatim}
\end{tscreen}

{\ttfamily ///} See: \ref{syncpage} {(Synchronization and Pagecount)}
\begin{tscreen}
\begin{verbatim}
###+++ Synchronization and Pagecount
if( status returned by printer and sync requested ){
    // APPSOCKET protocol
    // sync has the form sync@ (none), sync=ps, sync=pjl, ...
        if( appsocket ){
                command = "\n\r"
        } else {
                // decode status=language and determine sync
        if( sync = pjl and PJL ECHO available ){
            send PJL ECHO command to printer
                } else if( sync = ps ){
            send PS program to printer
                } else {
                        terminate with error;
                }
        do{
                send command and wait for timeout;
    } while( no response );

        if( appsocket ){
                close and reopen TCP/IP connection;
        }

    // pagecount has the form pagecount@ (none),
    //   pagecount=ps, pagecount=pjl, ...
    if( pagecount=language has value ) do {
                if( pagecount TRUE ){
                        set pagecount= pjl or ps depending on availability
                }
        if( pagecount = pjl and PJL INFO available ){
           send PJL INFO PAGECOUNT command to printer
                } else if( pagecount = ps ){
           send PS program to printer
                } else {
                        terminate with error;
                }
    } while( no pagecount response );

        if( appsocket ){
                close and reopen TCP/IP connection;
        }
}
###---
\end{verbatim}
\end{tscreen}

{\ttfamily ///} See: \ref{pjlinit} {(PJL Initialization)}
\begin{tscreen}
\begin{verbatim}
### PJL Initialization
if( PJL enabled ){
    language = "pjl_"
    foreach option in pjl_init=[...] {
       expand the option using the language value
       #+++ PJL OPTION ACTIONS +++
       if( option in pjl_vars_set=[ ... ]
         and option not in pjl_vars_except
         expand "@PJL SET OPTION=\%{option}"
         output = expanded string value
       } else {
         if( option value is a string ){
           output = expanded string value;
         }
       }
       // output has the form @PJL COMMAND ....
       if( COMMAND is in pjl_only=[ ... ]
           and not in pjl_except=[ ... ] ){
           send output to printer
       }
       #--- end PJL OPTION ACTIONS
    }
    if( !OF_mode ){
         foreach option in -Toption=value {
            if( option in pjl_user_opts ){
                #+++ USER PJL OPTIONS
                // join 'pjl_' and the option name
                expand 'pjl_' . option
                // perform PJL actions as above
                    #+++ PJL OPTION ACTIONS +++
                    ....
                    #-- PJL OPTION ACTIONS +++
                #--- USER PJL OPTIONS
            }
         }
         foreach option in -Zoption=value {
            if( option in pjl_user_opts ){
                // perform USER PJL actions as above
                #+++ USER PJL OPTIONS
                #--- USER PJL OPTIONS
            }
         }
    }
}

###--- PJL INITIALIZATION
\end{verbatim}
\end{tscreen}

{\ttfamily ///} See: \ref{textfile} {(Text File Conversion)}
\begin{tscreen}
\begin{verbatim}
// language is set to the type of job language
// - PS, PCL, TEXT, RAW, UNKNOWN
//  the first part of the job file is read and the filter takes
//  a (wimpy) guess at the job file based only on the first couple
//  of characters;  language is  be PJL, PS, or TEXT, or RAW
//  This is the same algorithm as the UNIX FILE utility

language = UNKNOWN
if( command line -c (binary) option present ){
    language = RAW;
} else if( -Zlanguage=xxx option present ){
    language=xxx
} else if( file is PS file ){
    language=PS
        if( file starts with PS EOJ (CTRL-D)
                and no_ps_eoj is set ){
                remove the PS EOJ
        } else {
                send a PS EOJ first
        }
} else if( file is PCL file ){
    language=PCL
        if( file starts with PCL EOJ (ESC E)
                and no_pcl_eoj is set ){
                remove the PCL EOJ
        }
} else if( file_util_path=/pathname ){
    use UNIX file utility to get file type
}

if( language = UNKNOWN and
    default_language option has value ){
    language = value of default_language;
}

if( language = TEXT ){
    if( text_converter=/path option has value ){
        run text converter on input
    } else if( printer does not support TEXT output ){
        exit with error;
    }
    language = value of text_converter_output option
}

if( language = UNKNOWN ){
    exit with error;
}
if( PJL ENTER supported ){
        use PJL ENTER command to select language;
        send nullpad NULLS to force full buffer condition
}
\end{verbatim}
\end{tscreen}

{\ttfamily ///} See: \ref{languageinit} {(Language Specific Initialization)}
\begin{tscreen}
\begin{verbatim}
// LANGUAGE SPECIFIC INITIALIZATIONS
if( language = PCL ){
    foreach option in pcl_init {
        ###+++ expansion 
        do expansion similar to PJL OPTION actions
            using "pcl_" prefix for option lookup;
        ###---
    }
    if( not in OF_MODE ){
        foreach option in -Toption do {
            if( option in pcl_user_vars=[ ... ] ){
            ###+++ expansion as above
            ###---
        }
        foreach option in -Zoption do {
            if( option in pcl_user_vars=[ ... ] ){
            ###+++ expansion as above
            ###---
        }
    }
    remove whitespace and expand string results;
} else if( language = PS ){
    ###+++ language specific actions as above,
      using the ps_ prefix for lookup 
    expand string results but do not remove whitespace
}
\end{verbatim}
\end{tscreen}

{\ttfamily ///} See: \ref{filetransfer} {(File Transfer and Error Status Monitoring)}
\begin{tscreen}
\begin{verbatim}
Transfer job to printer, reading error and other information
  back from the printer if enabled

if( language = PCL ){
    send PCL End of Job
} else if( language = PS ){
    send PS End of Job
}


// job terminaton

###+++ Synchronization and Pagecount as above
if( waitend ){
        if( sync requested previously ){
                if( sync with PJL ){
                        wait for end of job using UINFO;
                } else if( sync with PS ){
                        request status using ^T and wait for
                        printing to stop
                }
        }
        if( appsocket ){
                close and reopen connection;
        }
        get pagecount using previously descibed algorithm
}
        
###---

exit
\end{verbatim}
\end{tscreen}



\subsection{Options, Initialization and Setup
\label{setup}}

The
{\ttfamily ifhp}
filter is designed to work with the LPRng print spooler,
but will also work with other spooling systems.
The LPRng system will set the 
{\ttfamily PRINTCAP\_ENTRY}
environment variable to the current printcap value.
By convention,
the filter command line
{\ttfamily -Toptions}
are reserved for the print spooler to pass configurtion inforamtion
and the
{\ttfamily -Zoptions}
are passed by the user.
For example,
examine the following
{\ttfamily lpr}
command and printcap example:
\begin{tscreen}
\begin{verbatim}
Printcap:
pr:...
  :ifhp=opt1=value1,opt2=value2
  :if=/usr/ifhp -Topt1=value4,opt3=value3

Command:
lpr -Zopt4=value4

PRINTCAP_ENTRY envionment variable: 
  pr:...\n
    :ifhp=opt1=value1,opt2=value2\n
    :if=/usr/ifhp -Topt1=value4,opt3=value3\n

Resulting option list:

-Toptions:
  opt1=value4
  opt2=value2
  opt3=value3

-Zoptions:
  opt4=value4
\end{verbatim}
\end{tscreen}


When started,
the
{\ttfamily ifhp}
filter process the environment and command line options as follows.
\begin{enumerate}
\item If the
{\ttfamily PRINTCAP\_ENTRY}
environment variable has a value,
then this value is used to initialize the
{\ttfamily -Toption}
list.
\item If there is a
{\ttfamily -Toption}
command line option,
then these values are added to the
option list,
overriding values from the
{\ttfamily PRINTCAP\_ENTRY}
set.
\item The command line
{\ttfamily -Zoption}
list is generated by splitting the
{\ttfamily -Zoption}
command line option.
\end{enumerate}


The option lists are scanned for values for the
{\ttfamily debug},
{\ttfamily trace},
{\ttfamily config},
and
{\ttfamily model}
options.
These options
have the property that once they are set, then they cannot be modified
(i.e. - sticky values).

\label{model_from_option}
There is another,
and rather bizarre way to specify the printer model,
and that is the
{\ttfamily model\_from\_option}
option in the configuration file.
This option causes the command line options to be scanned,
and if there is a value for the command line option then it
is used as the model.
For example:
\begin{tscreen}
\begin{verbatim}
model_from_option=Q
\end{verbatim}
\end{tscreen}


The above setting will cause the model to be taken from the
{\ttfamily Q} option.
This can be used to select a configuration for the printer
based on values specifed by the user.


\subsubsection{Debug and Trace
\label{debug}
\label{trace}}

The value of the
{\ttfamily debug}
option sets the debugging level.
It can be increased, but not decreased.
The
{\ttfamily trace}
flag causes debugging information to be sent to STDERR (file descriptor 2)
as well as to the status file.


\subsubsection{Configuration File Paths
\label{configpaths}
\label{config}}

The main source of configuration information are the configuration files.
The
\begin{tscreen}
config=pathname,pathname
\end{tscreen}

option can be used to specify the list of configuration files to be read.
This can only be done using the
{\ttfamily PRINTCAP\_ENTRY}
{\ttfamily :ifhp}
entry or the
{\ttfamily -Tconfig=pathname,pathname}
command line option.


\subsection{Model Selection
\label{modelselect}
\label{model}}

The
{\ttfamily model=name}
option is used to establishes the model name for extracting
configuration information.
For details on this, see
\ref{configfiles} {(Configuration Files)}.

During initialization,
the
{\ttfamily -Toptions}
list is scanned for a
{\ttfamily -Tmodel=name}
entry.
Once the model name is set, it cannot be changed.
After this,
the configuration files are read,
and the first
{\ttfamily model=name}
option encountered will set the
{\ttfamily model}
option to
{\ttfamily name}.

The recommended method of model selection is to
specify it in the
LPRng printcap entry for the printer,
using the {\ttfamily :ifhp=...}
printcap field.
For example:
\begin{tscreen}
\begin{verbatim}
lp:ifhp=model=HP4,status@
  :if=/usr/local/ifhp

Resulting -Toption List:
 model=HP4
 status@
\end{verbatim}
\end{tscreen}


This will cause the
{\ttfamily -Toption}
list to be initialized as indicated,
and the
{\ttfamily model}
option value will be set to
{\ttfamily HP4}.

The next method is use a
{\ttfamily -Toption}
command line option.
\begin{tscreen}
\begin{verbatim}
lp:...
  :if=/usr/local/ifhp -Tmodel=HP4

Resulting -Toption List:
 model=HP4
\end{verbatim}
\end{tscreen}


This will cause the
{\ttfamily -Toption}
list to be initialized as indicated,
and the
{\ttfamily model}
option value will be set to
{\ttfamily HP4}.

Another method is to put the model information in a
{\ttfamily ./ifhp.conf}
file in the spool directory of the print queue.
The
{\ttfamily config=/pathname,/pathname,...}
option specifies the list of configuration files to read,
and the default value is:
\begin{tscreen}
\begin{verbatim}
config=./ifhp.conf,/etc/ifhp.conf,./ifhp.conf
\end{verbatim}
\end{tscreen}


If the model information is put in the 
{\ttfamily ./ifhp.conf}
configuration file,
the first reading will set the model name,
and the name is used to select the model information from the
{\ttfamily /etc/ifhp.conf}
file.
When the 
{\ttfamily ./ifhp.conf}
is reread,  the values in it can be used to override values from the
{\ttfamily /etc/ifhp.conf}
file.
For example:
\begin{tscreen}
\begin{verbatim}
./ifhp.conf:
  model=HP4
  lines=66

/etc/ifhp.conf:
[ hp* ]
 lines=60
[ apple* ]
 lines=20
\end{verbatim}
\end{tscreen}


When the
{\ttfamily ./ifhp.conf}
is first read,
it will establish
{\ttfamily model=hp}
(sticky) and 
{\ttfamily lines=66}.
When the
{\ttfamily /etc/ifhp.conf} file is read,
the model name matches the
{\ttfamily hp*} selector
(case insensive GLOB matching is used),
and the
{\ttfamily lines=60}
is selected and overrides the
{\ttfamily lines=66}
value.
Finally,
when the
{\ttfamily ./ifhp.conf}
file is reread,
{\ttfamily lines=66}
will establish the final value.


\subsection{Statusfile, Statusfile\_max, Statusfile\_min
\label{statusfile}
\label{statusfile_max}
\label{statusfile_min}}

The status file pathname is set by the command line
{\ttfamily -s /pathname}
or the
{\ttfamily statusfile=/pathname}
configurtion file entry.
If the
{\ttfamily /pathname}
file does not exist then it will not be created.
If the statusfile is larger than the
{\ttfamily statusfile\_max=max}
K bytes option value (default 8K),
then it will be truncated to
{\ttfamily statusfile\_min=min}
K bytes.


\subsubsection{Summmaryfile}

\label{summaryfile}
For historical and vintage software compatibility,
the
{\ttfamily summaryfile=/pathname}
or
{\ttfamily summaryfile=host\%port}
option will cause either a file to be open or a UDP network connection
established to the host  and port combination.
Debugging or trace information will be written to this file or network
connection as well, but the file will be truncated each time,
holding only the last line of trace information.




\subsection{Operation Configuration Options}

\label{optioninit}
\label{status}
\label{forcestatus}
\label{pjl}
\label{pcl}
\label{ps}
\label{text}
The
{\ttfamily -Toption=value}
and model configuration information is scanned
to set values of options which control filter activity.
There are some options whose related actions do not fall into
the simple model of string expansion.
These usually require generating commands dynamically,
or sending files containing font or setup information to the printer.
The following is a list of these options.


\subsubsection{status and forcestatus FLAGS}

These options have the side effect of enabling the reception of status
and error information from the printer.


\subsubsection{pjl, pcl, ps and text FLAGS}

These flags set the lanaguages that are recognized or processed by
the filter.


\subsubsection{crlf FLAG
\label{crlf}}

The
{\ttfamily crlf}
causes LF ({\ttfamily $\backslash$n}) to be translated to CR-LF
({\ttfamily $\backslash$r$\backslash$n}) sequences.
The following options will turn the
{\ttfamily ifhp}
filter into a simple CRLF translation filter.
Note that CRLF translation should have no effect
on PostScript, Text, or PCL files.
\begin{tscreen}
\begin{verbatim}
status@
pjl@
ps@
pcl@
text
text_converter_output@
text_converter@
crlf
\end{verbatim}
\end{tscreen}



\subsubsection{pjl\_job FLAG
\label{pjl_job}}

If PJL is enabled and this flag is SET,
a PJL JOB and PJL EOJ command will be generated
and sent to the printer.
The JOB command has the form:
\begin{tscreen}
@PJL JOB NAME = "..." {[} START = nnn {]} {[} END = mmm {]}
\end{tscreen}

The START and END values can be specified by
{\ttfamily -Zstart=nnn}
and
{\ttfamily -Zend=mmm}
command line options.
The EOJ command has must match the JOB command.
\begin{tscreen}
@PJL EOJ NAME = "..." {[} START = nnn {]} {[} END = nnn {]}
\end{tscreen}



\subsubsection{pjl\_enter FLAG
\label{pjl_enter}}

If PJL is enabled and this flag is SET,
a PJL ENTER LANGUAGE = xx command will be generated
when PCL or PS files are sent to the printer.
\begin{tscreen}
\begin{verbatim}
@PJL ENTER LANGUAGE = PCL
@PJL ENTER LANGUAGE = POSTSCRIPT
\end{verbatim}
\end{tscreen}



\subsubsection{nullpad STRING
\label{nullpad}}

Some older model HP printers required sending a large number of
NULL (0) characters to force commands in the input buffer to be read.
This can be done using the
{\ttfamily nullpad} option.

In practice,
this has turned out to be largely historical,
as most printers do not have this problem.


\subsubsection{pjl\_console FLAG
\label{pjl_console}}

When this flag is set,
PJL is available,
and the PJL
{\ttfamily RDYMSG}
command is supported,
then a short message will be put on the console.


\subsubsection{remove\_ctrl STRING
\label{remove_ctrl}}

The
{\ttfamily remove\_ctrl} string option species a list of (control) characters
that will be removed from PostScript jobs.
This solves the problem of jobs with embedded Control-T or Control-C
characters causing abnormal printer operation.
For example:
\begin{tscreen}
\begin{verbatim}
remove_ctrl=CT
\end{verbatim}
\end{tscreen}

would cause Control-C and Control-T characters to be removed.


\subsubsection{tbcp FLAG
\label{tbcp}}

The
{\ttfamily tbcp}
flag can be specified as a user option as well as a
configuration file option.
If the file type is PostScript and this flag is set,
then the file is transferred using the Transparent Binary Communication
Protocol.
(See the Adobe PostScript Language Reference Manual for details on
the protocol.)

At the start of the PostScript job,
the sequence {\ttfamily $\backslash$001} {\ttfamily M} is sent.
Afterwards,  all control characters in the set
{\ttfamily 0x01, 0x03, 0x04, 0x05,
0x11, 0x13, 0x14, 0x1C,}
are replaced by the two character sequence {\ttfamily $\backslash$001}
{\ttfamily X+'@'} or
{\ttfamily X+'$\backslash$100'} or
is sent.
For example:
\begin{tscreen}
\begin{verbatim}
C\001\003   ->  \001\115\103\001\101\001\103 or \001MC\001A\001C
\end{verbatim}
\end{tscreen}





\subsection{Synchronization and Pagecounts
\label{syncpage}
\label{pagecount}
\label{pagecount_interval}
\label{pagecount_timeout}
\label{pagecount_ps_code}
\label{sync}
\label{sync_interval}
\label{sync_timeout}}

Many printers are able to provide status information back to the
filter.
It is assumed that in these circumstances file descriptor 1
(FD1)
is
{\itshape bidirectional\/}
and status information can be read from it.
When the
{\ttfamily status}
or
{\ttfamily forcestatus}
option is TRUE,
then the filter assumes that it can read FD1.
In order to simplify configuration,
the
{\ttfamily ifhp}
filter will test FD1, and if it is not
a serial port or a network socket, will set
{\ttfamily status@}
or OFF.

However, there are some devices such as bidirectional printer ports
that will report status.
By setting
{\ttfamily forcestatus}
ON,
the filter can be forced to check for status.
This can have fatal or unexpected effects if status is not returned
correctly.

Synchronization is usually done in order to ensure that a previously
spooled job or printer action has completed correctly,
and the printer is ready to accept a new job.
It is usally carried out by sending a request to the printer to
echo a string back to the filter.
Clearly,
if the printer cannot provide status or echo values back,
then synchronization is impossible.

The value of the
{\ttfamily sync} option determines if a PJL ECHO command or simple PostScript 
program is used.
The PostScript program has the form:
\begin{tscreen}
$\backslash$004\%!PS-Adobe-2.0\\ 
( \%\%{[} echo: {\itshape TODSTR\/} ]\%\% ) print () = flush\\ 
$\backslash$004
\end{tscreen}


where {\itshape TODSTR\/} is replaced with the current Time of Day.

To control obtaining synchronization,
the
and
{\ttfamily sync\_timeout=nnn}
options are used.
The PJL or PS command is repeated at
{\ttfamily sync\_interval=nnn}
second intervals; if nnn is 0, then it is sent only once.
If synchronization is not obtained within
{\ttfamily sync\_timeout=nnn}
seconds, then the filter exits with an error status.
A 0 value or
{\ttfamily sync\_timeout@}
disables timeouts.

Pagecounts are used to do accounting and report the number of pages
used for a job.
Most printer have a hardware based pagecounter mechanism whose value
can be read by the appropriate PJL command or PostScript program.
For example, if the PJL INFO command
\begin{tscreen}
\begin{verbatim}
@PJL INFO PAGECOUNT
\end{verbatim}
\end{tscreen}

is supported by a printer,
the printer will return a status message containing the current pagecounter
value.
Printers that support PostScript may also be able to access the pagecounter
value using a PostScript program.
The exact details of the PostScript program vary from vendor to vendor and
the
{\ttfamily pagecount\_ps\_code=...}
option specifies the PostScript program to use.
For example:
\begin{tscreen}
\begin{verbatim}
pagecount_ps_code=
  /p {print} def ( %%[ pagecount: ) p
  statusdict begin pagecount end 20 string cvs p
  ( ]%% ) p () = flush
\end{verbatim}
\end{tscreen}


Pagecounting is supported by the
{\ttfamily pagecount=}{\itshape language\/},
{\ttfamily pagecount\_interval=nnn},
and
{\ttfamily pagecount\_timeout=nnn}
options.
The
{\ttfamily pagecount=}{\itshape language\/}
option enables pagecounting, and sets the language to be used.
Currently
{\ttfamily ps} (PostScript)
and
{\ttfamily pjl} (PJL)
are supported.
The pagecount request is repeated every
{\ttfamily pagecount\_interval=nnn}
second intervals; if nnn is 0, then it is sent only once.
If no pagecount value is obtained within
{\ttfamily pagecount\_timeout=nnn}
seconds, then the filter exits with an error.
A 0 value or
{\ttfamily sync\_timeout@}
disables timeouts.

Some printers do not correctly report end of job and must be polled
until the pagecount information stabilizes.
The PJL TEOJ (True End Of Job) PJL has been tried with limited success
on various printers to force End of Job reporting only when the
job has finished.
\begin{tscreen}
\begin{verbatim}
pjl_init=[ ... teoj ... ]
pjl_teoj=@PJL TEOJ=ON
\end{verbatim}
\end{tscreen}



\subsection{PJL Initialization
\label{pjlinit}
\label{endpage}
\label{startpage}
\label{pjl_only}
\label{pjl_except}
\label{pjl_vars_set}
\label{pjl_vars_except}
\label{pjl_user_opts}
\label{pjl_init}}

If a printer supports PJL,
the many printer operations can be initiated and controlled using
PJL commands.
Unfortunately,
not all printers support the same set of commands.
In addition,
not all printers support the same set of operations or options.
A PJL command has the form:
\begin{tscreen}
@PJL COMMAND OPTION OPTION ...
\end{tscreen}

A PJL variable is set using:
\begin{tscreen}
@PJL SET {\itshape var\/} = {\itshape value\/} ...
\end{tscreen}

The
{\ttfamily pjl\_only=[ ... ]},
{\ttfamily pjl\_except=[ ... ]},
{\ttfamily pjl\_vars\_set=[ ... ]},
and
{\ttfamily pjl\_vars\_except=[ ... ]}
options are used to control which PJL commands and which PJL variables
can be set.
The 
{\ttfamily pjl\_only}
variable lists the commands supported by the printer,
and the
{\ttfamily pjl\_except}
lists commands {\itshape not\/}
supported by the printer.
Before sending a PJL command,
the
{\ttfamily ifhp}
filter checks to make sure that the command name is in
{\ttfamily pjl\_only}
and not in
{\ttfamily pjl\_except}.
If the tests fail, then tne command is not sent.

Similarly,
when sending a command to set a PJL variable,
the
{\ttfamily pjl\_vars\_set}
and
{\ttfamily pjl\_vars\_except}
lists are checked to determine if the variable name is in
{\ttfamily pjl\_vars\_set}
and not in
{\ttfamily pjl\_except}
list.
If the tests fail, then tne command is not sent.

If PJL is enabled,
then the following actions are taken.
\begin{enumerate}
\item  PJL Universal Exit Lanaguage (UEL) {\ttfamily $\backslash$033\%-12345X} is sent to the printer.
This is required to ensure that the following PJL commands are
accepted.

\item  PJL JOB command is sent at the start of job.
The JOB command can be used to select pages or impressions to be printed.
If the
{\ttfamily -Zstartpage=nnn}
or
{\ttfamily -Zendpage=mmm}
option is present, then the PJL JOB command has the form:
\begin{tscreen}
@PJL JOB START=nnn END=mmm
\end{tscreen}
\item  The
{\ttfamily pjl\_init=[ ... ]}
value option is expanded using the PJL
({\ttfamily "pjl\_"}) language context as described above.
\item  The
{\ttfamily -Toption=value}s
and
{\ttfamily -Zoption=value}s
are scanned for matching option names in the 
{\ttfamily pjl\_user\_opts=[ ... ]} 
list.
If they are found,
then the options are recursively evaluated in the PJL language context.
The expansion alorithm will cause the option value to be used to set PJL
variables.
For example:
\begin{tscreen}
\begin{verbatim}
Configuration:
  pjl_vars_set=[ OUTBIN AUTOSELECT JAM=YES ]

Command
  ifhp -Zoutbin=upper,autoselect,jam

PJL command generated:
  @PJL SET OUTBIN=UPPER
  @PJL SET AUTOSELECT=ON
  @PJL SET JAM=YES
\end{verbatim}
\end{tscreen}
\end{enumerate}



\subsection{Text File Conversion
\label{textfile}
\label{default_language}
\label{file_util_path}
\label{text_converter}
\label{text_converter_output}
\label{text_tempfile}
\label{language}}

Many PostScript printers cannot handle text files,
and produce many hundreds of pages of garbage
output if they are sent to the printer without being translated
into PostScript.
Also,
while most PCL printers will accept text files and do a reasonable
job of printing them
some form of initialization strings or setup may need to be done.
Finally,
you might want to try using a
{\ttfamily MagicFilter}
that will convert just about any type of file into a PostScript file.


\subsubsection{Default Converter Program}

This method specifies that the default file type
will be
{\ttfamily text}.
If the simple {\ttfamily ifhp} type detection code cannot decide
what type of file this is,
it will invoke a converter program.
This operation is controlled by the following options.
\begin{description}
\item[{\ttfamily default\_language=text}] \mbox{}

When the default lanague is {\ttfamily text}
then the
{\ttfamily text\_converter} and
{\ttfamily text\_converter\_output} options are used.

\item[{\ttfamily text\_converter=/pathname}] \mbox{}

specifies the pathname of a text to language program.

\item[{\ttfamily text\_converter\_output=language}] \mbox{}

Specifies the output language of the conversion program.
Language can be
{\ttfamily ps},
{\ttfamily pcl},
{\ttfamily text},
{\ttfamily raw},
{\ttfamily unknown}

\item[{\ttfamily tempfile=/pathname}] \mbox{}

A temporary file location,  used to store
intermediate conversion results.
The
{\ttfamily /pathname}
value has the string
{\ttfamily XXXXXX}
appended to it and is used as input to the POSIX
{\ttfamily mktemp()}
function.

\end{description}


The print file language is determined using the following algorithm.
\begin{enumerate}
\item The default language is set to
{\ttfamily unknown}
or the
{\ttfamily default\_language=language} value if it exists.
\item If the command line
{\ttfamily -c}
(binary) option is present,
or the
{\ttfamily autodetect} configuration option is TRUE,
then the language is set to
{\ttfamily RAW}.
(The autodetect option is not recommended for general use).
\item If there is a
{\ttfamily -Zlanguage=value} command line option,
the language is set to
{\ttfamily value}.
\item Various simple checks to determine if the file is
Postscript
(language={\ttfamily ps})
or PCL
(language={\ttfamily pcl})
are performed.
These are the same checks that the UNIX
{\ttfamily file}
utility uses.
\item If the file type is 
{\ttfamily text}
then the
{\ttfamily text\_converter}
program is run to translate the file and the results stored in
the {\ttfamily tempfile}.
\end{enumerate}


One technique used with varying degrees of sophistication is to
use a general purpose file to PostScript conversion program.
These have generally been known as
{\itshape MagicFilters\/}, due to their high degree of flexibility. 


\subsubsection{Pseudo-MagicFilter Support}

As described above,
the various
{\itshape MagicFilter\/} packages can do conversion.
However, most of the time there is only a limited need for the
general purpose conversions.
This can be met by using the
{\ttfamily file} program,  which will determine the type of a file based on
its contents,
and having {\ttfamily ifhp} invoke a program based on the type of file found.
This method is used when
{\ttfamily default\_language=unknown}
and the
{\ttfamily file\_util\_path=/path}
and
{\ttfamily file\_output\_match=[ ... ]}
values are defined.
A typical configuration is shown below.
\begin{tscreen}
\begin{verbatim}
Configuration:
# 
#  Method 2 -
#    Use the file util and match the output
# file reports format information
#  glob text_output_format text_converter
#  - you do a glob match against pattern and use the converter
#
default_language=unknown
file_util_path=/usr/bin/file -
file_output_match = [
# glob   output converter
 *text*  ps     /usr/local/bin/a2ps -q -B -o-
 *gif*   ps     /usr/local/bin/gif2ps
 ]
\end{verbatim}
\end{tscreen}


The
{\ttfamily file\_output\_match}
entry consists of a list of lines containing
a {\itshape glob\/} pattern,
a language type ({\ttfamily ps}, {\ttfamily pcl}, or {\ttfamily raw}),
and a program to invoke to do the conversions.

The
{\ttfamily file}
utility is run and its output is matched against the specified
glob patterns.
When a match is found the specified program is run,
with STDIN attached to the original input file and its
STDOUT sent to the printer.

While this algorithm may appear to be overly complex, it
will handle a wide range of desired configurations.


\subsubsection{No Textfile Conversion Needed}

If your printer can handle text files without conversion,
but require PCL intialization, then the following combination
will simply set the language to
{\ttfamily pcl}:
\begin{tscreen}
\begin{verbatim}
text_converter@
text_converter_output=pcl
\end{verbatim}
\end{tscreen}



\subsubsection{Default Passthrough of Unknown File Types}

Your printer may be capable of handling a wide variety of job
formats.  If you want to simply pass through files of
unknown type or language then use:
\begin{tscreen}
\begin{verbatim}
text_converter@
text_converter_output=raw
\end{verbatim}
\end{tscreen}



\subsection{Language Specific Initialization
\label{languageinit}}

After determining the output file language type,
language specific operations are then carried out by
expanding the
{\itshape language\_\/}{\ttfamily \_init=[ ... ]}
options in the language context,
and then the options in the
{\ttfamily -Toption=value}
and
{\ttfamily -Zoption=value}
command line options.
The 
{\ttfamily -T}
options are expanded before the
{\ttfamily -Z},
allowing the 
{\ttfamily -Z} actions to override any set by the
{\ttfamily -T} actions.

As mentioned elsewhere,
the reason for the language specific processing is to allow
different actions for the same command line option,
depending on the file type that is being processed.
For example,  when processing a PCL file it might be necessary to send
PCL command strings and when processing a PostScript file,
you would need to send PostScript commands.


\subsection{File Transfer and Error Status Monitoring
\label{filetransfer}
\label{logall}
\label{pjl_error_codes}
\label{pjl_quiet_codes}}

If the printer can return status, i.e., the
{\ttfamily status}
or 
{\ttfamily forcestatus}
flag is set,
then the
{\ttfamily ifhp}
filter will read status information back from the printer.

If the
{\ttfamily logall}
flag is SET,
then all error messages will be written to the status or log file.

If the printer is returning PJL status information,
then this has a specific format:
\begin{tscreen}
\begin{verbatim}
@PJL UINFO DEVICE
CODE=nnnn
DISLAY="value"
...

@PJL UINFO JOB
START
...

@PJL UINFO JOB
END
...
\end{verbatim}
\end{tscreen}


The
{\ttfamily ifhp} program will extract the
{\ttfamily CODE}
and job start and end flags,
and log these as appropriate.

Unfortunately,
some PJL based printers are extremely verbose in their generation of status
messages.
In order to reduce the amount of logging of redundant information,
{\ttfamily ifhp}
will only record when a device status has
{\bfseries changed},
rather than when it has been reported.

The
pjl\_quiet\_codes={[} code code code {]}
value is used to suppress reporting of selected error codes.
If the error code is in the pjl\_quiet\_codes list,  then the error status
will not be reported to the user unless the
{\ttfamily logall}
option is set.
For example:
\begin{tscreen}
\begin{verbatim}
  pjl_quiet_codes=[ 10000 10001 10003 10023 10024 35078 ]
\end{verbatim}
\end{tscreen}


Also, there may be error codes which does not have a builtin error
message available.  New messages can be added using the
{\ttfamily pjl\_error\_codes}
option.
Its value is a list of lines, each line consisting of an error code
followed by the corresonding error message:
\begin{tscreen}
\begin{verbatim}
pjl_error_codes=[
   code=msg
   code=msg
   ...
]

Example:
  pjl_error_codes=[
     10000=powersave mode
     10001=Ready Online
     10002=Ready Offline
     10003=Warming Up
     10004=Self Test
     10005=Reset
  ]
\end{verbatim}
\end{tscreen}



\subsection{End of Job
\label{waitend}}

The {\ttfamily waitend} option controls the job termination sequence.
By default,
this will do the same work as the
{\ttfamily sync} operation,
and the option takes the same set of values.

If {\ttfamily waitend}
is suppressed using {\ttfamily waitend@},
then as soon as a job has been transferred,
the next step,
{\ttfamily pagecount},
will be attempted.
If the print job has not finished at this point,
then erroneous page counts will be reported.

When using the {\ttfamily appsocket} protocol,
then suppressing {\ttfamily waitend} will cause no error messages from the printer to
be reported.




\subsection{Tektronix Phaser and AppSocket Support
\label{appsocket}}

The Tektronix Phaser PostScript printers uses the AppSocket protcol
for sending a job to the printer over a network connection.
The
{\ttfamily appsocket} flag enables this operation.
The protocol is (briefly):
\begin{enumerate}
\item  The printer listens for UDP packets on port 9101
and for TCP/IP connections on port 9100.
\item  When a UDP packet is recieved on port 9101, then a reply
packet containing the status is returned to the originator's
address.
This packet contains an status indication,
in a {\itshape undefined\/} format.
\item  To send a job to the printer,  a TCP/IP connection is opened to port
9100,
and a PostScript job is sent.
Only a single job can be sent at a time - a EOJ (CTRL-D)
will terminate input and flush all following jobs.
\item Return status will be sent in the reverse direction until the job
has completed,
at which point the connection will be closed.
\end{enumerate}


To use this protocol,
the printer TCP/IP address and port must be specified using the
{\ttfamily -Tdev=host\%port} option;
usually port is 9100.
Also,
the printer device in the printcap entry should be {\ttfamily lp=/dev/null}.

When using the Appsocket protocol,
the {\ttfamily ifhp} filter will open a UDP port and use it to send
query packets to the printer UDP port 9101.
In addition,
it will try to open a connection to port 9100.
When a connection has been established,
and pagecount has been determined,
the connection will be close and reopened.

After job transfer,
the connecion will be {\ttfamily half-closed}.
That is,
the {\ttfamily shutdown()} facility will be used to cause the TCP/IP connection
to be set to closed for transmission but open for reception.
The printer will send status information until the job is completed,
and then close the connection.

If page count information is needed,
the {\ttfamily ifhp} filter will then reopen the connection and get the page count information.


\section{Banners and OF Mode Operations
\label{banner}
\label{banner_file}
\label{page_width}
\label{page_length}}

The OF mode is enabled by the command line -Fo flag or by
the file name of the executable containing the "of" string.

When operating in the OF mode,  the filter uses the value of the
banner key to determine what to do with input.  If banners are
disabled
({\ttfamily banner@}),
then input is simply passed directly to the
output.
The banner\_suppressed flag allows you to suppress banner printing
until explicitly requested by a user using the -Zbanner flag.
\begin{description}
\item[{\ttfamily banner=pcl}] \mbox{}

Uses a built-in PCL banner generator.  Pretty simple output.

\item[{\ttfamily  banner=ps }] \mbox{}

Using information from the command line options,  generates
PostScript line which set the values of PostScript variables.
Then the contents of the file specified by
{\ttfamily banner\_file=/path}
are appended.
\begin{tscreen}
\%!PS-Adobe-2.0 \\ 
/Seq (number) def \\ 
/Job (banner) def \\ 
/Host (HOST) def \\ 
/Class (CLASS) def \\ 
/User (USER) def \\ 
/Date (DATE) def \\ 
/Name (NAME) def \\ 
/Line (LINE) def \\ 
/{\bfseries X} ({\itshape command line\/} {\ttfamily -X} {\itshape option value\/}) def 
\end{tscreen}


\item[{\ttfamily banner=text}] \mbox{}

Puts out a simple text based banner.
Uses the command line
{\ttfamily -w width} and {\ttfamily -l length}
command line options to set the page width in columns
and pagelength in lines.
If these are not set,
the configuation options
{\ttfamily page\_width=width}
and
{\ttfamily page\_length=length}
values are used.

\item[{\ttfamily banner=/path}] \mbox{}

Opens and copies the file directly to the printer.

\item[{\ttfamily  banner=$|$/path }] \mbox{}

Forks and EXECs the executable specified by
{\ttfamily /path},
with the same arguments as those passed to the filter.
The executable output is sent to the printer.

\end{description}



\section{Predefined Options}

The following is a list of predefined options. \\ 
{\ttfamily \ref{appsocket} {(appsocket FLAG)}}{\ttfamily ~~~~~~~~~~~~~~~~} Use Tektronix AppSocket Protocol \\ 
{\ttfamily \ref{banner} {(banner=LANGUAGE)}}{\ttfamily ~~~~~~~~~~~~~~~} Enable OF banner printing using LANGUAGE \\ 
{\ttfamily \ref{banner_file} {(banner\_file=PATHNAME)}}{\ttfamily ~~~~~~~~~~} PATHNAME of PostScript banner file \\ 
{\ttfamily \ref{config} {(config=PATHNAMES)}}{\ttfamily ~~~~~~~~~~~~~~} Configuration file pathnames \\ 
{\ttfamily \ref{crlf} {(crlf FLAG)}}{\ttfamily ~~~~~~~~~~~~~~~~~~~~~} Do LF to CRLF translation \\ 
{\ttfamily \ref{debug} {(debug FLAG)}}{\ttfamily ~~~~~~~~~~~~~~~~~~~~} Debugging level \\ 
{\ttfamily \ref{default_language} {(default\_language=LANGUAGE)}}{\ttfamily ~~~~~} Default job file language (ps, pcl, raw, text, etc) \\ 
{\ttfamily \ref{endpage} {(endpage=NNN)}}{\ttfamily ~~~~~~~~~~~~~~~~~~~} PJL JOB command END = NNN value \\ 
{\ttfamily \ref{file_util_path} {(file\_util\_path=PATHNAME)}}{\ttfamily ~~~~~~~} Pathname of the UNIX file utility \\ 
{\ttfamily \ref{forcestatus} {(forcestatus FLAG)}}{\ttfamily ~~~~~~~~~~~~~~} Force status reading from the printer if set \\ 
{\ttfamily \ref{language} {(language=LANGUAGE)}}{\ttfamily ~~~~~~~~~~~~~} Specify job file language to be used (ps, pcl, raw, text, etc) \\ 
{\ttfamily \ref{logall} {(logall FLAG)}}{\ttfamily ~~~~~~~~~~~~~~~~~~~} Log all status reports from printer if set \\ 
{\ttfamily \ref{nullpad} {(nullpad=COUNT)}}{\ttfamily ~~~~~~~~~~~~~~~~~} Send COUNT nulls to force full buffer condition \\ 
{\ttfamily \ref{model} {(model=NAME)}}{\ttfamily ~~~~~~~~~~~~~~~~~~~~} Specify model name for configuration selection \\ 
{\ttfamily \ref{model_from_option} {(model\_from\_optin=X)}}{\ttfamily ~~~~~~~~~~~~} Specify model name using a command line option value \\ 
{\ttfamily \ref{no_ps_eoj} {(no\_ps\_eoj FLAG)}}{\ttfamily ~~~~~~~~~~~~~~~~} No PostScript EOJ (CTRL-D) at start of job \\ 
{\ttfamily \ref{no_pcl_eoj} {(no\_pcl\_eoj FLAG)}}{\ttfamily ~~~~~~~~~~~~~~~} No PCL EOJ (CTRL-D) at start of job \\ 
{\ttfamily \ref{page_length} {(page\_length=LINES)}}{\ttfamily ~~~~~~~~~~~~~} Number of lines on a text page for banner printing \\ 
{\ttfamily \ref{page_width} {(page\_width=COLUMNS)}}{\ttfamily ~~~~~~~~~~~~} Number of columns on a text page for banner printing \\ 
{\ttfamily \ref{pagecount} {(pagecount=LANGUAGE)}}{\ttfamily ~~~~~~~~~~~~} Enable pagecounting using the specified lanague (pjl, ps) \\ 
{\ttfamily \ref{pagecount_interval} {(pagecount\_interval=SECONDS)}}{\ttfamily ~~~~} Send pagecount command at SECONDS interval \\ 
{\ttfamily \ref{pagecount_ps_code} {(pagecount\_ps\_code=STRING)}}{\ttfamily ~~~~~~} PostScript code to get pagecount information \\ 
{\ttfamily \ref{pagecount_timeout} {(pagecount\_timeout=SECONDS)}}{\ttfamily ~~~~~} Timeout getting pagecount after SECONDS \\ 
{\ttfamily \ref{pcl} {(pcl FLAG)}}{\ttfamily ~~~~~~~~~~~~~~~~~~~~~~} Printer supports PCL if set \\ 
{\ttfamily \ref{pcl_user_opts} {(pcl\_user\_opts=LIST)}}{\ttfamily ~~~~~~~~~~~~} User PCL options supported \\ 
{\ttfamily \ref{pjl} {(pjl FLAG)}}{\ttfamily ~~~~~~~~~~~~~~~~~~~~~~} Printer supports PJL if set \\ 
{\ttfamily \ref{pjl_console} {(pjl\_console FLAG)}}{\ttfamily ~~~~~~~~~~~~~~} Printer supports messages on console \\ 
{\ttfamily \ref{pjl_error_codes} {(pjl\_error\_codes=LIST)}}{\ttfamily ~~~~~~~~~~} PJL error messages for error codes \\ 
{\ttfamily \ref{pjl_except} {(pjl\_except=LIST)}}{\ttfamily ~~~~~~~~~~~~~~~} Do not allow these PJL commands \\ 
{\ttfamily \ref{pjl_init} {(pjl\_init=LIST)}}{\ttfamily ~~~~~~~~~~~~~~~~~} PJL initializations to be done \\ 
{\ttfamily \ref{pjl_job} {(pjl\_job FLAG)}}{\ttfamily ~~~~~~~~~~~~~~~~~~} PJL JOB and EOJ supported \\ 
{\ttfamily \ref{pjl_only} {(pjl\_only=LIST)}}{\ttfamily ~~~~~~~~~~~~~~~~~} Allow only these PJL commands \\ 
{\ttfamily \ref{pjl_user_opts} {(pjl\_user\_opts=LIST)}}{\ttfamily ~~~~~~~~~~~~} Allow only these user PJL commands or variables to be set \\ 
{\ttfamily \ref{pjl_vars_except} {(pjl\_vars\_except=LIST)}}{\ttfamily ~~~~~~~~~~} Do not allow these PJL variables to be set \\ 
{\ttfamily \ref{pjl_vars_set} {(pjl\_vars\_set=LIST)}}{\ttfamily ~~~~~~~~~~~~~} Allow these PJL variables to be set \\ 
{\ttfamily \ref{ps} {(ps FLAG)}}{\ttfamily ~~~~~~~~~~~~~~~~~~~~~~~} Printer supports PostScript (ps) \\ 
{\ttfamily \ref{ps_user_opts} {(ps\_user\_opts=LIST)}}{\ttfamily ~~~~~~~~~~~~~} Support these PostScript user options \\ 
{\ttfamily \ref{read_write} {(read\_write FLAG)}}{\ttfamily ~~~~~~~~~~~~~~~} Open a file or device read/write\\ 
{\ttfamily \ref{remove_ctrl} {(remove\_ctrl=LIST)}}{\ttfamily ~~~~~~~~~~~~~~} Remove these characters from PostScript jobs \\ 
{\ttfamily \ref{startpage} {(startpage=NNN)}}{\ttfamily ~~~~~~~~~~~~~~~~~} PJL JOB command START = NNN value \\ 
{\ttfamily \ref{status} {(status FLAG)}}{\ttfamily ~~~~~~~~~~~~~~~~~~~} Printer supplies status information \\ 
{\ttfamily \ref{statusfile} {(statusfile=PATHNAME)}}{\ttfamily ~~~~~~~~~~~} Status file pathname \\ 
{\ttfamily \ref{statusfile_max} {(statusfile\_max=NNN)}}{\ttfamily ~~~~~~~~~~~~} Status file has maximum size of NNN Kbytes \\ 
{\ttfamily \ref{statusfile_min} {(statusfile\_min=NNN)}}{\ttfamily ~~~~~~~~~~~~} Status file has truncated size of NNN Kbytes \\ 
{\ttfamily \ref{summaryfile} {(summaryfile=PATHNAME)}}{\ttfamily ~~~~~~~~~~} Summary file pathname \\ 
{\ttfamily \ref{sync} {(sync FLAG)}}{\ttfamily ~~~~~~~~~~~~~~~~~~~~~} Synchronize printer if set \\ 
{\ttfamily \ref{sync_interval} {(sync\_interval=SECONDS)}}{\ttfamily ~~~~~~~~~} Send synchronization request at SECONDS interval \\ 
{\ttfamily \ref{sync_timeout} {(sync\_timeout=SECONDS)}}{\ttfamily ~~~~~~~~~~} Timeout synchronization request after SECONDS \\ 
{\ttfamily \ref{tbcp} {(tbcp FLAG)}}{\ttfamily ~~~~~~~~~~~~~~~~~~~~~} Use Transparent Binary Communications Protocol for PostScript files \\ 
{\ttfamily \ref{text} {(text FLAG)}}{\ttfamily ~~~~~~~~~~~~~~~~~~~~~} Printer supports text mode \\ 
{\ttfamily \ref{text_converter} {(text\_converter=PATHNAME)}}{\ttfamily ~~~~~~~} Pathname of text conversion program \\ 
{\ttfamily \ref{text_converter_output} {(text\_converter\_output=LANGUAGE)}}{\ttfamily } Job language of text converter output \\ 
{\ttfamily \ref{text_tempfile} {(text\_tempfile=PATHNAME)}}{\ttfamily ~~~~~~~~} Temporary file pathname template \\ 
{\ttfamily \ref{trace} {(trace FLAG)}}{\ttfamily ~~~~~~~~~~~~~~~~~~~~} Put error and trace messages on STDERR if set \\ 


\section{Configuration Files
\label{configfiles}}

Run time options are provided by the
command line arguments and values in the configuration  files.
By convention,
the configuration files are named
{\ttfamily ifhp.conf}.

In order to provide a flexible run time configuration facility,
the location of the configuration files is specifed as follows.
\begin{enumerate}
\item The default list of configuration files is:\\ 
{\ttfamily ./ifhp.conf,/etc/ifhp.conf,./ifhp.conf}
\item The command line option\\ 
{\ttfamily -Tconfig=/path,/path,...}\\ 
can be used to override the default list of configuration files.
\end{enumerate}


Here is a section of a simple configuration file.
\begin{tscreen}
\begin{verbatim}
# languages
pcl
statusfile=status
status
sync=pcl
sync_interval=20
# we force pagecounting off
#pagecount=pcl
pagecount@
[ HP4Si ]
status@
end
[ HP5Si ]
pjl
sync=pjl
\end{verbatim}
\end{tscreen}


The configuration file is used to set flags, option values, and to cause
various
{\ttfamily ifhp}
actions.
The file has the following structure.
\begin{enumerate}
\item   Blank lines and lines starting with \# are ignored.
\item   Keys or flags start in column 1.
The syntax is similar to the LPRng and BSD
file.
\begin{tscreen}
\begin{verbatim}
Syntax             Equivalent To    Class
flag               flag=1           (FLAG)
flag@       flag=0           (FLAG)
flag=val           flag=val (string value) STRING
flag=] v v  ... [          LIST
\end{verbatim}
\end{tscreen}
\item Flags are used for options which take a TRUE/FALSE, 0/1, or ON/OFF
value, and
{\ttfamily ifhp}
will substitute the appropriate form or perform the
assocated action if the flag is TRUE.
\item Strings are used to set options which require a multicharacter value.
The special form
{\ttfamily flag@}
is used to indicate that the operation
related to this option is not to be performed.
\item Lists are used to specify a list of options which can be flags or string
values.
Lists have the property of
{\itshape recursive evaluation\/}
which means that the individual items in the list will be acted upon in order.
This is discussed later in detail.
\item The list entries are separated by whitespace,
and each entry can have the form v, v@,
v=word, or v1\#word, where word does not contain whitespace or
the {[}{]} characters.
\item Flag values can be spread over multiple lines.  Lines starting with
whitespace, are treated as a continuation of the previous
flags line value.  For example:
\begin{tscreen}
\begin{verbatim}
# set string x value 'first\n  second\n  third'
x= first
  second
  third
# set list y value [ f1 f2 ]
y=[ f1
 f2 ]
\end{verbatim}
\end{tscreen}
\item Selection lines have the form:
\begin{tscreen}
\begin{verbatim}
[ glob glob ... ]
\end{verbatim}
\end{tscreen}

Selection lines divide the configuration file into sections
corresponding to a particular printer model.   Configuration
information is extracted from a file until either an 'end' line
or a selection line is encountered.

\item An 'end' line consisting of the single work 'end' will terminate
reading lines from a configuration file.
\item  As the configuration file is read,  flag lines and values are accumulated.
Later values encountered in the file will replace earlier values.
\end{enumerate}



\subsection{Configuration Selection}

The recommended format for a  configuration file is to put common
(default) flag settings at the start of the configuration file,
followed by selection sections with overridding and additional flag
values.

To allow a single file to be used for multiple printer configurations,
you can specify that a section of the file is to be used ONLY by
a various models of printers.  This is is controlled by the value
of the 'model' flag and selection lines of the form:
\begin{tscreen}
\begin{verbatim}
  [ glob glob ... ]
\end{verbatim}
\end{tscreen}


The first occurrence of a 'model=xx' line in either the -T options
or the configuration file will set the model flag value to 'xx'.

The 'model' value is matched against the modelglob values using
GLOB matching.  For example:
\begin{tscreen}
\begin{verbatim}
hp*      matches hp4 hp5x
hp[45]   matches hp4 hp5, but not hp5x
hp[3-6]* matches hp3, hp5, hp5x, but not hpiii
\end{verbatim}
\end{tscreen}


If a matching entry is found,  successive lines will be used until
either another selection line or an 'end' line is encountered.  An
'end' line will terminate reading the current file, and the next
configuration file will be read.

The default list of configuration files is:
\begin{tscreen}
\begin{verbatim}
ifhp.conf, /etc/ifhp.conf, ifhp.conf
\end{verbatim}
\end{tscreen}


This arrangement allows you to read the ifhp.conf file to get
various model settings,  scan the /etc/ifhp.conf file to get the
generic ones,  and then to rescan the local ifhp.conf file to
provide overrides to values set in the /etc/ifhp.conf file.


\subsection{Option Use}

Options and their values are used to control printer operation.
There are two types of options:
those with a predefined or
{\itshape builtin\/}
meaning to the
{\ttfamily ifhp}
filter and those which
are simply used to supply values for expansion during operation.

The builtin options are listed in later sections,
and their use is explained.
These options can have flag, string, or list values as is appropriate
to their corresponding actions.


\subsection{Recursive List Expansion}

During normal operation,
the
{\ttfamily ifhp}
filter will perform an operation by producing a set of strings
which will be sent to the printer or output device.
These strings may be obtained by using the values of predefined or builtin
option names,
or by expanding a LIST value.

A LIST value has the form X={[} v1 v2 ... {]}.
When a list value is expanded
each of v1, v2 is examined in turn
and the corresponding action or string substitution or builtin evaluation
is carried out.
If v1 has a string value and is not recognized as a builtin or special option
then normally the string value will be used.
\begin{tscreen}
\begin{verbatim}
t1=[ p1 p2 p3=end ]
p1=this is
p2=[ p3 p4 ]
p3=a
p4=test
p3=living\020\%{p3}
\end{verbatim}
\end{tscreen}


For example,
when expanding
{\ttfamily t1}
each of
{\ttfamily p1}
and
{\ttfamily p1}
is in turn expanded.
This will produce the strings
{\ttfamily "this is"},
{\ttfamily "a"},
{\ttfamily "test"}
and
{\ttfamily "living end"}
in turn.

Some LIST variables are used in
printer language specific contexts
and their values are processed appropriately.
For example,
pjl\_init={[}...{]} specifies a set of operations to be carried
out for printers that support PJL,
and pcl\_init={[}...{]} for PCL
printers.  The expansion of the LIST entries is done in the language
specific context.
For PJL this requires that the output be well formed PJL commands,
and for PCL that all whitespace be removed.

The context dependent expansion is required because sometimes it
is necessary to do operations both using PJL and PCL or PJL and PS
combinations to ensure correct printer operation.
For this reason,  during expansion the language name and an underscore
is prefixed to the list entry name,  and this is used as the option name during the search.

For example,  suppose that we have:
\begin{tscreen}
\begin{verbatim}
    pjl_init=[ test ]
    pcl_init=[ test ]
    initstr=NO
    pjl_initstr=@PJL ECHO YES
    pcl_initstr=\033(*yeS
\end{verbatim}
\end{tscreen}


When PJL initialization is done, the 'pjl\_test' LIST will be
expanded, and the PJL string '@PJL ECHO YES' will obtained.
When PCL language specific processing is done,  then the
$\backslash$033(*yeS string will be obtained.


\subsection{String Expansion}

String values are encoded using a
simple PERL/C language like method.  The $\backslash$ (escape) character
introduces a replacement string.  This has the form:
\begin{description}
\item[Standard Character Replacement] \mbox{}

{\ttfamily  $\backslash$f $\backslash$r $\backslash$n $\backslash$t $\backslash$nnn}
where nnn are 3 octal digits are replaced
by the standard PERL or C character substutions.

\item[Option Value Replacement] \mbox{}

{\ttfamily $\backslash$\%format$\{$option$\}$    $\backslash$\%format[option]}

The option name will be relaced by the formatted option value.

\item[Option Search Order] \mbox{}

The option value is located using a simple set of rules.
\begin{enumerate}
\item During a recursive option evaluation,
expanding
{\ttfamily option=word}
will push the
{\ttfamily option=word}
combination onto an evaluation stack.
This stack is searched in oldest to newest order for a match.
\item If no match was found,
and the expression has the form
{\ttfamily $\{$option$\}$}
then the
{\ttfamily -Zoption=value}
command line options will be searched for a match.
\item If no match was found,
then the
{\ttfamily -Toption=value}
command line options will be searched for a match.
This allows the 
{\ttfamily $\{$option$\}$}
to start searching from the -Z command line options and
{\ttfamily [option]}
to start searching from the -T command line options.
\item If no match was found,
then the configuration information is searched.
\item If no match was found,
then the value is considered undefined,
and a 
{\ttfamily "0"}
value is used.
\end{enumerate}


\item[Format] \mbox{}

The format specifies how the value is to appear,
and is similar to the printf format usage:
\begin{tscreen}
\begin{verbatim}
   %[-][0][length[.precision]][format]
\end{verbatim}
\end{tscreen}


The default format is \%d, ie, $\backslash$\%$\{$val$\}$ would be $\backslash$\%d$\{$val$\}$.
The numerical formats supported are: \%d, \%o, \%x, \%X, \%e, \%f, and \%g;
The \%s format use the option string value.

The format is usually not required, except when fractional values of point sizes
or string substition rather than numerical substition is required.

\end{description}


For example:
\begin{tscreen}
\begin{verbatim}
Configuration:
  pjl_user_opts=[ ... outbin intray ...]
  pjl_outbin=@PJL SET OUTBIN=\%s{outbin}
  intraynum=4
  pjl_intray=@PJL SET INTRAY=\%{intraynum}

Command:
  ifhp -Zoutbin=LEFT
\end{verbatim}
\end{tscreen}


During PJL language processing,
the 
{\ttfamily -Z}
command line options
will be scanned for options which appear in the
{\ttfamily pjl\_user\_opts}
list.
The
{\ttfamily -Toutbin=LEFT}
option will be found and will be expanded in the PJL context
by prefixing
{\ttfamily pjl\_}
and looking for a string or list value.
The
{\ttfamily pjl\_outbin}
option will be found,
and the
{\ttfamily @PJL SET OUTBIN=$\backslash$\%s$\{$outbin$\}$}
string will be expanded.

Now we need to search for the
{\ttfamily outbin}
value.
We first search for it on the evaluation stack,
but there is nothing there yet.
We then search the
{\ttfamily -Z}
options and find the
{\ttfamily outbin}
value,
and substition yields
{\ttfamily @PJL SET OUTBIN=LEFT}.

Next, the
{\ttfamily intray}
option is found and
{\ttfamily pjl\_intray}
is expanded,
which needs a value for
{\ttfamily intraynum}.
This is found in the configuration information,
and finally in
{\ttfamily @PJL SET INTRAY=4}.
\begin{tscreen}
\begin{verbatim}
cpi=5.5
pcl_cpi=\033\%3.2f{cpi}D
\end{verbatim}
\end{tscreen}


During PCL option expansion,
we might need to expand the
{\ttfamily pcl\_cpi}
option.
When the
{\ttfamily pcl\_cpi=$\backslash$033$\backslash$\%3.2f$\{$cpi$\}$D}
string is expanded,
the result is
{\ttfamily $\backslash$033$\backslash$\%5.00D}.
If the user has specified
{\ttfamily -Tcpi=9}
on the command line then the result is
{\ttfamily $\backslash$033$\backslash$\%9.00D}.


\subsection{Language Context}

The Tifhp filter sends initialization and configuration commands to the
printer.
Depending on the language,
these commands have specific forms and requirements.
Rather than requiring the user to remember the details, Tifhp uses the following conventions.


\subsubsection{PJL Language}

A PJL command has the form
{\ttfamily @PJL OPCODE ...}.
A command must start with
{\ttfamily @PJL}
and consist of a single string value.
You cannot patch together options to make a single PJL command.
\begin{enumerate}
\item Before sending any PJL command to the printer,
the PJL Universal Exit Command
({\ttfamily $\backslash$033\%-12345X})
string is sent to the printer.
\item Because not all printers support all PJL commands,
the Tifhp filter performs a couple of checks using the
{\ttfamily pjl\_only}
and
{\ttfamily pjl\_except}
configuration options.
The OPCODE must appear in the
{\ttfamily pjl\_only}
list and not in the
{\ttfamily pjl\_except}
list.
\item Leading and trailing whitespace is removed,
and all characters are converted to uppercase.
\item Individual commands have a newline
({\ttfamily $\backslash$n}) appended to them before being sent to the printer.
\end{enumerate}



\subsubsection{PCL Lanaguage}

When sending PCL initialization strings to a printer,
it is essential to send nothing that could cause a printable character to
be sent before the actual file contents.
Such output could cause the location and positioning of text to be altered
in unexpected ways.
To avoid this,
the following steps are taken when processing PCL strings.
\begin{enumerate}
\item Before any PCL string is sent to the printer,
the PCL End of Job
({\ttfamily $\backslash$033E}) string is sent to the printer.
\item First,
all whitespace (blanks, tabs, etc) are removed from the string value.
\item Next, all escaped values are substituted.
At this point you can
{\itshape force\/}
printable strings containing whitespace into the output by using the
{\ttfamily $\backslash$nnn}
escape mechanism.
\end{enumerate}



\subsubsection{PostScript Language}

The PostScript language processing is very minimal,
as there are few problems sending PostScript to a printer.
\begin{enumerate}
\item Before sending any PostScript initialization strings,
the PostScript End of Job indicator
({\ttfamily $\backslash$004} or Control-D) is sent.
\item Strings are then expanded and the escape sequences are substituted.
\item Individual strings have a newline
({\ttfamily $\backslash$n}) appended to them before being sent to the printer.
\end{enumerate}



\section{Font Download Support}

For historical reasons,
there is support for downloading a font or other file to the
printer.
A large amount of the necessary operations are now in the
{\ttfamily ifhp.conf}
file.

The
{\ttfamily font\_download}
built-in option supports downloading as described below.


\subsection{PCL Font Downloading}

The following shows the a typical
{\ttfamily ifhp.conf}
file which has PCL font downloading enabled.
\begin{tscreen}
\begin{verbatim}
#
# Fonts and Font Downloading
#  fontid is used to set the current font
pcl_init=[ ... font ... ]

# combination command
pcl_font=[ delete_fonts font_id font_download font_primary ]

# font control
#
font_op=0
pcl_font_op=\033*c\%{font_op}F
pcl_delete_fonts=\033*c0F

font_id=1
pcl_font_id=\033*c\%{font_id}D

# set primary font
font_primary=1
pcl_font_primary=\033(\%{font_primary}X

# font directory
pcl_fontdir=/usr/local/lib/fonts

#default font file
font=c1201b.10
\end{verbatim}
\end{tscreen}


To allow users to download a font and have it set up for PCL use,
the 
{\ttfamily pcl\_init}
option should include the
{\ttfamily font}
option in an appropriate position in the intitialization sequence.
As shown above,
this will get expanded into the
{\ttfamily pcl\_delete\_fonts},
{\ttfamily pcl\_font\_id},
{\ttfamily pcl\_font\_download} (which is has built-in support),
and the
{\ttfamily pcl\_font\_primary}
options,
which are expanded in order.

The
{\ttfamily pcl\_font\_download} is supported by the builtin operation which will
find the
{\ttfamily pcl\_fontdir}
directory value
and a value for the
{\ttfamily font}
variable,
using values from the
{\ttfamily -Z}
and
{\ttfamily -T}
and configuration information in that order.
If no
{\ttfamily font}
value is found,
no font will be downloaded.
For example:
\begin{tscreen}
\begin{verbatim}
lpr -Tfont=font1,font2
\end{verbatim}
\end{tscreen}


When the
{\ttfamily pcl\_font\_download}
option is expanded,
it will generate the pathnames
{\ttfamily /usr/local/lib/fonts/font1}
and
{\ttfamily /usr/local/lib/fonts/font2},
open these files,
and send their contents directly to the printer.


\subsection{PS Font Downloading}

PostScript font downloading is supported in a similar manner to
PCL font downloading.
\begin{tscreen}
\begin{verbatim}
#
# Fonts and Font Downloading
# 
ps_init=[ ... font ... ]

# combination command
pcl_font=[ font_download ]

# font directory
ps_fontdir=/usr/local/lib/fonts

#default font file
font=font.ps.10
\end{verbatim}
\end{tscreen}


In a similar manner to the PCL font downloading,
when the
{\ttfamily ps\_init}
list is expanded,
the
{\ttfamily ps\_font}
entry will be expanded in turn.
If the {\ttfamily -Zfont=ZapDingbat.ps} is specified,
then the
{\ttfamily /usr/local/lib/fonts/ZapDingbat.sp}
file will be opened and downloaded to the printer.


\subsection{PJL File Downloading}

In a similar manner to the above font downloading,
you can specify a configuration or other setup file that should be
sent to the printer as part of the PJL setups.
The following configuration shows how to set this up.
\begin{tscreen}
\begin{verbatim}
#
# PJL Initialization File Downloading
#  fontid is used to set the current font
pjl_init=[ ... setup  ... ]

setup=initval
font=\%s{setup}
# setup directory
pjl_fontdir=/usr/local/lib/fonts
pjl_setup=[ font_download ]
\end{verbatim}
\end{tscreen}


The above configuration will cause the value of the
{\ttfamily setup}
{\ttfamily -Z},
{\ttfamily -T}
or configuration option to be used.


\section{Banner Printing}

One of the more difficult administrative issues is whether to print
banners (job separators) or to save the large amount of wasted
paper, time and effort.
The LPRng and
{\ttfamily ifhp}
combination provide a rather esoteric set of methods to generate banners,
at least one of which should be suitable for your application.

You should be aware that some printers have the obnoxious habit of
generating their own banner pages when jobs are transferred via
the RFC1179 protocol.
You should consult the manufacturers documentation and take the
necessary steps to turn printer banner page generation off.


\subsection{Banner Printing with LPRng}

The following steps need to be done to configure LPRng to print
banners using
{\ttfamily ifhp}.
\begin{enumerate}
\item In order to print a banner,
the LPRng print spooler will require a user name
for the banner page to be present in the print job.
However,
since users can request
{\itshape no banner\/}
via various options on the print spooler interface,
LPRng provides the handy
{\itshape force\_banner\/}
option to always force a banner to be generated,
even if the user has specifically requested that one
{\itshape not\/}
be generated.
This is useful for preventing the
{\itshape disappearing print job\/}
syndrome in large installations.
\item Next,
LPRng must be configured to generate banners.
The
{\ttfamily sh}
(suppress header)
option must be off
({\ttfamily sh@}).
\item At this point you need to decide if you want LPRng to generate
the banner of the
{\ttfamily ifhp}
filter to generate the banner.
If you want LPRng to generate the banner,
you can specify a
{\ttfamily banner}
generation program,
and inform
{\ttfamily ifhp}
{\bfseries not}
to generate a banner (the default).
\begin{tscreen}
\begin{verbatim}
Printcap:
lp:
  :sh@
  :banner=/usr/local/filters/bannergen
  :if=ifhp -Tbanner
\end{verbatim}
\end{tscreen}
\item If you want
{\ttfamily ifhp}
to generate a banner,
you do not have LPRng generate a banner and
enable banner printing by
{\ttfamily ifhp}.
You also can specify the
{\ttfamily sb}
or short banner option,
which will cause a very short dummy banner to be generated.
This will be ignored by the
{\ttfamily ifhp}
filter.
\begin{tscreen}
\begin{verbatim}
Printcap:
lp:
  # short banner, save effort
  :sh@:sb
  :if=ifhp -Tbanner
\end{verbatim}
\end{tscreen}
\item Finally,
you have your choice of PCL,
PostScript and even Text banners.
These can be specified using
{\ttfamily banner=}{\bfseries language}:
\begin{tscreen}
Printcap:
lp: \\ 
~~\# short banner, save effort \\ 
~~:sh@:sb \\ 
~~:if=ifhp -Tbanner={\bfseries language} \\ 
\end{tscreen}
\end{enumerate}



\subsection{Stand Alone Banner Program}

Occasionally it is useful to be able to generate a banner
in
{\itshape standalone\/}
mode.
For example,
you might want to generate a banner
when using an LPRng
{\itshape bounce queue\/}
to perform filtering operations before forwarding jobs to another
printer.
To do this requires a stand-alone banner printer.
{\ttfamily ifhp} can be configured to do this by using:
\begin{tscreen}
ifhp -Tbanner\_only
\end{tscreen}

In addition,
you can specify the type of banner you want using:
\begin{tscreen}
ifhp -Tbanner\_only={\bfseries language}
\end{tscreen}


Lastly,
in order to be {\itshape vintage software compatible\/},
if the ifhp program is invoked as the
{\ttfamily banner}
program,
this is effectivly the same as
\begin{tscreen}
ifhp -Tbanner\_only
\end{tscreen}


For example,
to use this with a bounce queue to an
{\ttfamily hp4} printer,
the following printcap entry might be used:
\begin{tscreen}
\begin{verbatim}
# for clients, force spooling to server
lp:lp=lp@server
# server
lp:server
  :bq=raw@printer
  :ifhp=model=hp4
  :generate_banner
  :banner=/usr/local/filters/ifhp -Tbanner_only
  :if=/usrlocal/filters/ifhp
  :of=/usrlocal/filters/ifhp
\end{verbatim}
\end{tscreen}



\section{Accounting}

In Academic institutions, avoiding printing accounting has been
regarded as a challenge,  an ongoing game of fat cat and poor starving
mouse, between the Adminstration and the downtrodden, poor, overcharged
student.  The following is a lighthearted ramble down the dark lane of
printing accounting.

We will disregard the fact that if most students put as much effort
into their studies as in finding ways to avoid accounting procedures
then they would be Rhodes Scholar material,  but I digress...


\subsection{Page Accounting Algorithm}

The accounting procedures put into the LPRng and the ifhp filters may
appear to be extraordinarily complex,  but believe me, they are not.
Firstly, we make the assumption that the printer has some sort of
non-volatile page counter mechanism that is reliable and impervious to
power on/off cycles.  Without this mechanism the enterprising student
ummm... user will simply turn off the printer.  Software that prescans
jobs for line counts and pages is notoriously unreliable,  given even
the most modest efforts of users to hide these procedures.   The cost
of running a PostScript simulator simply to do accounting has its
flaws; without ensuring that the simulator has all of the interesting
security loopholes closed, such as opening files, etc.,  it can become
a trap door to hell for the system administrator.

Secondly,  we must make the assumption that the student... uhhh...
user will not be able to tinker with the page counter mechanism, i.e.-
they will not be able to roll back the odometer on the printer,
{\itshape for the duration of a single job\/}.
I will digress and point out that a student
actually did this for a challenge;  it only took him a couple of weeks
of study and a fully equipped microcontroller lab, and two (2) laser
printers which he ruined in the experiment.
HP was not amused when we
sent them back under warranty,  claiming that this our 'normal lab usage.'

Lastly,  you should not mind a small amount of pilferage, or a few
pages here and there being charged to the wrong account.

The basic mechanism the ifhp filter uses is to record the page
counter value at the start and end of each part of a print job. Each
record has the form:
\begin{tscreen}
\begin{verbatim}
start -qpagecounter ....
end  -ppages -qpagecounter -telapasedtime ....
\end{verbatim}
\end{tscreen}


When we use the OF filter and/or banners,  we will see the
individual jobs bracketed by the OF filter records:
\begin{tscreen}
\begin{verbatim}
start -q100 -Fo -kcfA100taco -uuser -hhost -R...  
start -q101 -Ff -kcfA100taco -uuser -hhost -R...  
end  -p1 -q102 -Ff -kcfA100taco -uuser -hhost -R...  
start -q102 -Ff -kcfA100taco -uuser -hhost -R...
end  -p3 -q105 -Ff -kcfA100taco -uuser -hhost -R...  
end  -p5 -q105 -Fo -kcfA100taco -uuser -hhost -R...
\end{verbatim}
\end{tscreen}


It should be clear from the above that all we need to do is to add up
the values for the -Fo (OF) filter lines and we are done.

Unfortunately,  this is too simplistic.  If for some reason the job is
killed or terminates due to error conditions,  the OF filter may not
get to finish its work.  Thus,  we may see the following:
\begin{tscreen}
\begin{verbatim}
start -q100 -Fo -kcfA100taco -uuser -hhost -R...  
start -q101 -Ff -kcfA100taco -uuser -hhost -R...  
start -q110 -Fo -kcfA101taco -uuser -hhost -R...
\end{verbatim}
\end{tscreen}


This is a clear indication that the user's job has been terminated.  In
this case we need to use the differences between pagecounters of the start
records to do accounting.

There is a caveat to all of this;  that is the problem of the last dead
job in the list.  If the last line in the accounting file is:
\begin{tscreen}
\begin{verbatim}
start -q110 -Fo -kcfA101taco -uuser -hhost -R...
\end{verbatim}
\end{tscreen}

is the last job finished or did it abort?


\subsection{You Used 2000 Pages, Out of Quota}

Now we move on to the problem of real time accounting.  Due to limited
budgets, etc., many institutions would like to strictly enforce limits
on paper use by students. As jobs are printed their accounts should be
docked for the amount of paper use.  One way to do this is to have an
external accounting procedure update a shared database.  The
ifhp
filter
has provision for a shell script to be invoked
at the start and end of print job;
this is done by both the OF and IF filter.  Thus, we can blithely
assume that there is a central database carefully getting updates
from the LPRng software, probaly from dozens of different printers,
and updating the accounting information,
and that this program can query the database,
check limits,
and terminate printing if the limits are exceeded.

The first question to be asked is simple:  is this worth it?
Perhaps doing accounting as a batch job once an hour/four times
a day/once a day is cheaper than buiding an running such a database.
If it costs \$5K/year for the database software, you might just consider
ignorng the 10,000 pages that get lost in the shuffle and use
a simple set of awk/sed/perl scripts to update a database once
an hour.


\subsection{Bad Jobs - Who Do We Bill?}

We inevitably run into an interesting question:
what happens if a job does not complete correctly?

If you use the completion of the OF filter as a success status, I have
to point out that many students... ummm... users soon find ways to send
jobs to the printer that will cause it to lock up after their output
has been printed. These jobs require power cycling of the printer and
restarting the filter; a bit extreme, perhaps, but it has happened.

I suggest that you simply adopt a 'bill to last user of record'
attitude,  using the pagecount information as follows:
\begin{tscreen}
\begin{verbatim}
start OF -- starting point for THIS job
start IF --  nice information, but not useful
start IF --
end OF -- ending point for this job - can record infomaiton

start OF --
if no end OF for previous job,  then treat as end OF and
          update accounting.
\end{verbatim}
\end{tscreen}


Now somebody is sure to complain that they got charged for a bunch of
pages that they did not use.  This is inevitable;  always carry a
can of oil for the squeaky wheels.  I might make the observation that
once is accident, twice is coincidence, but three times is malice;
be wary of the constant complainer and check out not only him but
also his co-workers.


\subsection{How Do We Update The Database}

I suggest that database update be done as follows:
maintain a 'last page reported' record for each printer in the
database.

When a successful job reports in,  check to see that the recorded pagecount
for the printer is in agreement with the one that is reported.

If this is not the case then you have had some unsuccessful jobs.
In this case I strongly recommend that you have a means to request the
accounting reporting program to go back through the accounting file and
find the last report for the page counter value and try to backtrack
through the accounting files.  The accounting file is one of the first
things to be attacked by students... Ummm...  users.  It should NOT be
kept on and NFS exported or mounted file system.  It should be
carefully pruned and copied, perhaps on an hourly basis.

Now some adminstrators have fallen in love with network based printers;
do not believe ANYTHING that comes over a network connection without
some form of authentication;  PGP has some very nice Public Key
mechansims for handling this.  This is a major weakness in using a
database for keeping track of accounting - a weak authentication
mechanism may lead to denial of service attacks by students flooding
the database with bogus print usage reports;  suddenly NOBODY can print
and the adminstrator is driven to turning off accounting.

Good luck.  I am never suprised when I encounter yet another wrinkle in
this area.


\subsection{Accounting Shell Script}

The 
\begin{tscreen}
\begin{verbatim}
accounting=/pathname
\end{verbatim}
\end{tscreen}

specifies a program to run
at the start and end of the
{\ttfamily ifhp} activity.
For an example of a simple script,
see the accounting.sh script in the distribution.


\subsection{Pagecounter Values}

The only reliable way to do page counting in the face of
PostScript,
PCL,
and other mystical printer job languages is to query the printer
and get the current value of a hardware page counter.
Unfortuately,
this may not be a trivial matter.
\begin{enumerate}
\item The page counter may not be updated in real time.
This means that you may need to wait a couple of seconds until you are
sure that the pages have been recorded.
Usually this occurs when the pages leave the print engine
and are put in the output tray.
\item Printers do job batching,
and when they report job completion the job is still being printed.
\item Some printers report
{\itshape impressions\/},
i.e.- sides of pages printed,
rather than pages.
If you are doing duplex printing then you may find that your
paper count and your page (impression) count differ.
\item Some printers simply lack page reporting.
\end{enumerate}


Given these problems,
it is more than reasonable to reconsider the need for accounting,
or to work closely with the printer vendor to understand the
interactions of print jobs and reporting of page counts.


\section{Monitoring Printer Operation}

Normally the
{\ttfamily ifhp}
filter will write error and trace messages to the
{\ttfamily statusfile}
specified by the command line
{\ttfamily -s}
option or the
{\ttfamily statusfile=pathname}
configuration entry.

However,
there may be a need to get information sent to a central or other
location for system administration purposes.
The
{\ttfamily summaryfile=host\%port}
option will cause {\ttfamily ifhp} to  open a UDP connection 
to the specified port on the remote host and send the error and
trace information to that location as well.

The
{\ttfamily monitor}
program include in the LPRng
and {\ttfamily ifhp}
distributions is a template for writing a program to use
this information.


\section{HP JetDirect Card Support}

The  HPJetDirect  card or external
JetDirect box can  be configured through the printer front
panel  or through a set of network files.  Here is a summary
of  the  methods  used  from  UNIX  systems, or when you are
desperate, to configure the printer.


\subsection{TCP/IP Network Address}

You can set the network address from the front panel.
Reset  the printer; use the MENU, +-, SELECT keys as follows:
\begin{tscreen}
\begin{verbatim}
 MENU  -> MIO MENU (use MENU to display MIO MENU)
 ITEM  -> CFG NETWORK=NO*
 +     -> CFG NETWORK=YES
 ENTER -> CFG NETWORK=YES*
 ITEM  -> TCP/IP=OFF* (use ITEM to display TCP/IP)
 +     -> TCP/IP=ON
 ENTER -> TCP/IP=ON*
 ITEM  -> CFG TCP/IP=NO* (use ITEM to display TCP/IP)
 +     -> CFG TCP/IP=YES
 ENTER -> CFG TCP/IP=YES*
 ITEM  -> BOOTP=NO*
         (Enable BOOTP if you want to - see below)
 ITEM  -> IP BYTE 1=0*
         This is IP address MSB byte.
         Use +- keys to change value, and then ENTER to change
         Use ITEM keys to get IP BYTE=2,3,4
 ITEM  -> SM BYTE 1=255*
          This is the subnet mask value
         Use +- keys to change value, and then ENTER to change
         Use ITEM keys to get IP BYTE=2,3,4
 ITEM  -> LG BYTE 1=255*
         This is the Syslog server (LoGger) IP address
         Use +- keys to change value, and then ENTER to change
         Use ITEM keys to get IP BYTE=2,3,4
 ITEM  -> GW BYTE 1=255*
         This is the subnet gateway (router) IP address
         Use +- keys to change value, and then ENTER to change
         Use ITEM keys to get IP BYTE=2,3,4
 ITEM  -> TIMEOUT=90
          This is the connection timeout value.  It puts a limit
         on time between connections.  A value of 10 is reasonable.
\end{verbatim}
\end{tscreen}



\subsection{BOOTP Information}

If  you have a bootp server, you can put this information
in  the  bootptab  file.   To  use this, you must enable the
bootp  option  on  the printer.  The T144 option specifies a
file to be read from the bootp server.  This file is read by
using  the  TFTP  protocol, and you must have a TFTPD server
enabled.  Here is a sample bootptab entry.
\begin{tscreen}
\begin{verbatim}
# Example /etc/bootptab: database for bootp server (/etc/bootpd).
# Blank lines and lines beginning with '#' are ignored.
#
# Legend:
#
#       first field -- hostname
#                       (may be full domain name)
#
#       hd -- home directory
#       bf -- bootfile
#       cs -- cookie servers
#       ds -- domain name servers
#       gw -- gateways
#       ha -- hardware address
#       ht -- hardware type
#       im -- impress servers
#       ip -- host IP address
#       lg -- log servers
#       lp -- LPR servers
#       ns -- IEN-116 name servers
#       rl -- resource location protocol servers
#       sm -- subnet mask
#       tc -- template host (points to similar host entry)
#       to -- time offset (seconds)
#       ts -- time servers
#
# Be careful about including backslashes where they're needed.  Weird (bad)
# things can happen when a backslash is omitted where one is intended.
#
peripheral1:
:hn:ht=ether:vm=rfc1048:
:ha=08000903212F:
:ip=190.40.101.22:
:sm=255.255.255.0:
:gw=190.40.101.1:
:lg=190.40.101.3:
:T144="hpnp/peripheral1.cfg":
\end{verbatim}
\end{tscreen}


If  you  are  using the T144 option, you will need to create
the  configuration file.  The sample configuration file from
the HP Direct distribution is included below.
\begin{tscreen}
\begin{verbatim}
#
# Example HP Network Peripheral Interface configuration file
# 
# Comments begin with '#' and end at the end of the line.
# Blank lines are ignored.  Entries cannot span lines.

# Name is the peripheral (or node) name.  It is displayed on the peripheral's
# self-test page or configuration plot, and when sysName is obtained through
# SNMP.  This name can be provided in the BOOTP response or can be specified
# in the NPI configuration file to prevent the BOOTP response from overflowing
# the packet.  The domain portion of the name is not necessary because the
# peripheral does not perform Domain Name System (DNS) searches.  Name is
# limited to 64 characters.

name: picasso

# Location describes the physical location of the peripheral.  This is the
# value used by the interface for the MIB-II sysLocation object.  The default
# location is undefined.  Only printable ASCII characters are allowed.
# Maximum length is 64 characters.

location: 1st floor, south wall

# Contact is the name of the person who administers or services the peripheral
# and may include how to contact this person.  It is limited to 64 characters.
# This is the value used by the interface for the MIB-II sysContact object.
# The default contact is undefined.  Only printable ASCII characters are
# allowed.  Maximum length is 64 characters.

contact: Phil, ext 1234

# The host access list contains the list of hosts or networks of hosts
# that are allowed to connect to the peripheral.  The format is
# "allow: netnum [mask]", where netnum is a network number or a host IP
# address.  Mask is an address mask of bits to apply to the network number
# and connecting host's IP address to verify access to the peripheral.
# The mask usually matches the network or subnet mask, but this is not
# required.  If netnum is a host IP address, the mask 255.255.255.255 can
# be omitted.  Up to ten access list entries are permitted.

# to allow all of network 10 to access the peripheral:
allow: 10.0.0.0  255.0.0.0

# to allow a single host without specifying the mask:
allow: 15.1.2.3

# Idle timeout is the time (in seconds) after which an idle
# print data connection is closed.  A value of zero disables
# the timeout mechanism.  The default timeout is 90 seconds.

idle-timeout: 120

# A community name is a password that allows SNMP access to MIB values on
# the network peripheral.  Community names are not highly secure; they are
# not encrypted across the network.  The get community name determines which
# SNMP GetRequests are responded to.  By default, the network peripheral
# responds to all GetRequests.  The get community name is limited to 32
# characters.
#
# For hpnpstat and hpnpadmin, the community name can be stored in
# /usr/lib/hpnp/hpnpsnmp.

get-community-name: blue

# The set community name is similar to the get community name.  The set
# community name determines which SNMP SetRequests are responded to.  In
# addition, SetRequests are only honored if the sending host is on the
# host access list.  By default, the network peripheral does not respond
# to any SetRequests.  The set community name is limited to 32 characters.
#
# The set community name can come from /usr/lib/hpnp/hpnpsnmp
# if it is the same as the get community name.  We recommend that the
# set community name be different from the get community name though.

set-community-name: yellow

# SNMP traps are asynchronous notifications of some event that has occurred.
# SNMP traps are useful only with network management software.  Traps are
# sent to specific hosts and include a trap community name.  Up to four
# hosts can be sent SNMP traps.   The trap community name is limited to
# 32 characters.  The default name is public.

trap-community-name: red

# The SNMP trap destination list specifies systems to which SNMP
# traps are sent.  Up to four IP addresses are allowed.  If no
# trap destinations are listed, traps are not sent.

trap-dest: 15.1.2.3
trap-dest: 15.2.3.4

# The SNMP authentication trap parameter enables or disables the sending
# of SNMP authentication traps.  Authentication traps indicate that an SNMP
# request was received and the community name check failed.  By default,
# the parameter is off.

authentication-trap: on

# The syslog-facility parameter sets the source facility identifier that the
# card uses when issuing syslog messages.  Other facilities, for example,
# include the kernel (LOG_KERN), the mail system (LOG_MAIL), and the spooling
# system (LOG_LPR).  The card only allows its syslog facility to be configured
# to one of the local user values (LOG_LOCAL0 through LOG_LOCAL7).  The
# selectable option strings, local0 through local7 (configured to LOG_LOCAL0
# through LOG_LOCAL7, respectively) are case insensitive.  The default
# syslog-facility for the card is LOG_LPR.

syslog-facility: local2

# This parameter allows the card to treat hosts on other subnets as if the
# hosts were on the card's subnet.  This parameter determines the TCP
# Maximum Segment Size (MSS) advertised by the card to hosts on other subnets
# and affects the card's initial receive-window size.  The card will use a
# TCP MSS of 1460 bytes for local hosts, and 536 bytes for a non-local host.
# The default is off, that is, the card will use the maximum packet sizes
# only on the card's configured subnet.
#
# The configuration utility does not allow access to this parameter.  If you
# want to configure it, you must manually edit the NPI configuration file
# and add it to the bottom of the entry for the network peripheral.

subnets-local: on

# This parameter affects how the card handles TCP connection requests from
# the host.  By default, the JetDirect MPS card will accept a TCP connection
# even if the peripheral is off-line.  If this parameter is set to "on", then
# the card will only accept a TCP connection when the peripheral is on-line.

old-idle-mode: off
\end{verbatim}
\end{tscreen}



\subsection{Timeouts}

You should be aware that the
{\ttfamily idle-timeout}
value in the configuration file will override the value
entered on the control panel of the printer.

Also,
the
{\ttfamily @PJL SET TIMEOUT = NNN}
command will override this value as well.

\end{document}
