Copyright 1988-1991 Network Computing Devices, Inc.  All rights reserved.
An unpublished work.

#ident "@(#)READMORE	14.1	91/02/26"

INTRODUCTION

This directory contains all of the pieces needed to be able to send
data to a printer connected to an NCD X terminal.  There are several
scenarios considered here:

 1) The one we use here at NCD -- Apple LaserWriter printers accessed
    via a BSD-based spooler like the one found in SunOS or ULTRIX.

 2) HP DeskJet, HP LaserJet or "dumb" ASCII printers accessed via a BSD
    spooler.  Note that these HP printers are basically "dumb" printers
    in that they do not report any status back to the terminal.  In
    this sense they are like any generic dot-matrix printer.

 3) Any of the above printers with the data being provided by
    pass-through mode in an xterm.  This is much like having an ASCII
    terminal with a printer connected.


COMPILING AND INSTALLING THE CODE

There are two basic pieces of software needed to perform output to a
printer connected to an NCD X terminal.  The first is the program to
talk to the terminal and pass data to the serial port.  The second is
an input filter for the spooler.  There are other utilities as well.

These programs are provide on all tar format NCDware tapes in a
directory called src/lp-spooler.  All of the executable programs can be
compiled using make.  This has been tested on SunOS on both a Sun 3 and
Sun 4 (Sparc) and ULTRIX on both a DECsystem and VAX, Some useful rules
in the makefile are listed in the table below and are referenced in the
following paragraphs:

    all       builds all executables for TCP/IP access

    dnet      builds all executables for DECnet access (ULTRIX)

    install   installs the executables and shell scripts in
              /usr/local/bin/ncdprint

If you want the executables installed in /usr/local/bin/ncdprint,
simply make sure the directory exists and type:

    make install

If you'd like it installed somewhere else, type:

    make install DESTBIN=somewhere-else

In any case, this should compile the various utilities and place them in
the proper directory.  What you should then have is:

    file        what it does
    --------    ----------------------------------------------------
    add_prt     adds links to if.sh for spooled printer
    banner      prints big letters for header pages
    cat2ncd     like cat to the NCD auxiliary serial port
    chr         simple control character generator
    del_prt     deletes links to if.sh for spooled printer
    if.sh       input filter for BSD-derived spoolers
    lw_maint    LaserWriter maintenance utility
    ps2ncd      bidirectional communications with LaserWriter on NCD
    print       prints arguments without spaces or newline
    readn       simple utility to read n chars from stdin
    xlog        start logging in an xterm


CONFIGURING THE TERMINAL

Before any printing can be done the NCD X terminal must be configured
properly for printing.  This is especially important for printers other
than the Apple LaserWriter where there is no interactive feedback from
the printer.  In the case of these "dumb" printers, an error in the
terminal configuration can result in lost printer output.

To configure the terminal's serial port parameters see the NCDware
Advanced User's Manual.  Briefly, here's what you need to set
(parameters are in the Auxiliary Port Parameters section of the Serial
Port Parameters setup menu):

    Parameter       Suggested Value
    -------------   ---------------

    Use Port        Printer Daemon
    Data Bits              8
    Stop Bits              1
    Parity               None
    Handshake          XON/XOFF
    Baud Rate         (see note)
    Hangup Method        None

All parameters should be set to match the attached printer.  The values
listed above are generally the right ones, but check your printer
documentation to make sure.  The Baud Rate parameter should be set to
match the printer as well.  Make this as high as you can.

For the Apple LaserWriter IINTX you can go as high as 38.4K baud.  See
the section near the end of this file for details about how to set the
line speed.

After the terminal is configured, connect the printer.  Use a null
modem adapter and a male to male cable.  See the User's Manual that
came with the NCD terminal for the required pins.  If you don't want to
worry about it, use a 25 line cable.

Once the printer is connected, test the connection by sending some data
using the cat2ncd or ps2ncd command.  For example, for an HP LaserJet
on an NCD terminal named ncdu20:

    (date; chr FF) | cat2ncd ncdu20

and make sure the page prints and that is has the proper date on it.
The FF is needed to cause the page to be ejected by the printer.
Otherwise it just sits there waiting for more data.

For an Apple LaserWriter on NCD terminal ncdu145:

    (echo %!; echo /str 32 string def; \
     echo statusdict begin str printername print end) | ps2ncd ncdu145

This will print a message of the form:

91-02-12 06:12:15: ps2ncd: ncdu145: LaserWriter II NTX

if the printer is accessible.  The text after the last colon is the
printer name stored in the printer.


SIMPLY PRINTING

If spooling is not required, the only program needed is ncdprint.c and
one or both of it's executable forms -- cat2ncd and ps2ncd.  Cat2ncd,
as it's name implies, simply sends the bytes presented to it's standard
input to the serial port of the NCD X terminal.  It can be used to send
text to the connected printer by simply identifying the terminal's
hostname or IP address (DECnet name or address if built using make
dnet):

    cat2ncd ncdu20 < /etc/passwd

or

    cat2ncd 192.43.154.79 < /etc/passwd

When cat2ncd is used remember to provide all printer control characters
in the input stream.  For example, on the HP Laser Jet printers you may
have to provide an escape sequence or form feed to cause the last page
to be printed as well as providing a sequence to have CR mapped to CR+LF.

So, for example, to send a window dump to an HP LaserJet connected to
ncdu20:

    xwd | (xpr -device lj -rv -scale 3; chr ESC \& l 0 H) | cat2ncd ncdu20

The chr utility used in the example was developed because sometimes
it's hard to preserve control characters and escape sequences through
some editors and because shell scripts containing printer controls are
hard to print correctly.  The program chr (built from chr.c) takes a
series of characters as arguments and simply sends them to it's
standard output.  The input arguments can be either single characters
or multiple character representations of control characters.  Single
character arguments are simply printed.  Control characters recognized
and processed are LF, FF, DEL, BEL, and ESC.  Other multiple character
arguments are ignored.

If you have an Apple LaserWriter or equivalent PostScript printer, you
don't want to just send characters to it using cat2ncd, but instead
want to use ps2ncd.  This program (also compiled from ncdprint.c) knows
how to manage the conversation which must take place to successfully
send a PostScript document to the printer.  It initializes the printer,
sends the PostScript data read from it's standard input, and notes any
errors that occur at the printer on it's standard error.  When the job
is done, it waits for the last page to print and then exits.

Our window dump example above can be done more simply with ps2ncd:

    xwd | xpr -device lw -scale 3 | ps2ncd ncdu145

Like cat2ncd, ps2ncd takes one argument -- the hostname or address of
the NCD X terminal.  It's standard error displays any messages that are
returned by the printer.  For example, if the printer runs out of paper
you would see messages like:

90-02-05 12:12:28: psncd: ncdu82: %%[ PrinterError: out of paper ]%%
90-02-05 12:14:31: psncd: ncdu82: %%[ PrinterError: no paper tray ]%%

on the standard error of the ps2ncd process.

The first two fields in messages like this are a time stamp.  This is
followed by the program name and the network display station name.  The
final text is what the printer returned.

All time stamps produced are formatted in this strange way (YY-MM-DD
and HH:MM:SS) to facilitate sorting/merging of multiple output logs.

Remember that the Apple LaserWriter is a PostScript printer.  You
cannot simply send it text (unless you've put it into one of the funny
printer emulation modes it supports, in which case you should think of
it as a dumb printer).  If you send it text, you'll get errors on the
standard error of ps2ncd.  For example typing:

    date | ps2ncd ncdu145

results in:

91-02-12 06:19:27: ps2ncd: ncdu145: %%[ Error: undefined; OffendingCommand: Tue ]%%
91-02-12 06:19:27: ps2ncd: ncdu145: %%[ Flushing: rest of job (to end-of-file) will be ignored ]%%


PRINTING TEXT ON A POSTSCRIPT PRINTER

If text needs to be printed, there are several text to PostScript
filters around.  The two that we have tested with are Adobe's
TranScript and Barry Brachman's lwf.  The later is available on the
net.  If you can't get a copy, out Technical Support staff will gladly
send you a copy -- send mail to support@ncd.com or call 415-694-0650
and ask for Technical Support.  We can't put it on the NCDware tapes
due to restrictions listed in lwf.c.

For example, with lwf the correct command pipeline for sending text to
the printer is:

	date | lwf -s11 | ps2ncd ncdu20

The -s11 argument tells lwf to use 11 point text.  This gets 68 lines
of 87 characters on a page.  Using -s12 will only get 79 characters
across the page.


PASS THROUGH MODE

Pass through mode (screen data being passed through to the printer) can
be accomplished using the logging feature of X11R4 xterm.  One simple
way is to just turn on logging and when you're done turn it off and
print the file.  You can, however, cause the logging to be done
directly to the spooler or the printer.

There are two parts to this:  defining the log file and controlling
when logging starts and ends.

The log file can be defined either using X resources or via an escape
sequence.  The resource to control the log file is the logFile (class
Logfile) resource of the vt100 (class VT100) widget.  For example, the
resource specification:

    *VT100.Logfile: |(cat;chr FF)|cat2ncd ncdu20

can be used for any of the non-PostScript printers discussed here.
With a PostScript printer:

    *VT100.Logfile: |lwf -s11|ps2ncd ncdu145

The other way is via escape sequences and that's what the xlog script
uses.  To use xlog instead of the resource specification, simply type:

    xlog on "|(cat;chr FF)|cat2ncd ncdu20"
	.  -\
	.    >---- these lines are printed
	.  -/
    xlog off

When X resources are used to define the log file you can use the Main
Options menu of xterm to turn logging on and off.  The Main Options
menu is normally accessed using Ctrl and the left mouse button.

Using xlog with only the on argument causes the "logged" data to be
sent to the spooler via lpr.


SPOOLING

BSD-based spoolers use a file called /etc/printcap to control which
printers are connected to a system and which remote printers are known
on the system (for more information see your vendor-supplied system
administration documentation).  When a printer connected to an NCD X
terminal it should be configured as if it were locally connected to
some system.  Other systems should be set up to send jobs to the
controlling system.  The NCD X terminal can arbitrate between several
requesters, allowing only one at a time, but configuring printers as if
they were local to several systems has not been extensively tested and
is discouraged.

After you have your printer connected and tested as described above,
you'll need to add an entry in the controlling system's /etc/printcap
file.  Once that's done, define the input filter and enable the printer
for spooling.  These are both discussed a little later on.


The Printcap File

The printcap entries we use in testing look like:

	lablw|Apple LaserWriter on NCD unit ncdu145:\
		lf=/usr/adm/lpd-errs:\
		if=/usr/local/bin/ncdprint/if%lwup%ncdu145:\
		sh:\
		sd=/usr/spool/lablw:\
		lp=/dev/lablw:\
		pw#80:

The first attribute (lf=) specified is the log file.  This file will
contain the standard error of the command pipeline used to print the
job after it has been printed or has failed.  For jobs already
completed it should contain lines that tell when a job was started,
when it finished, and any errors associated with that job.  It is
optional -- see your vendor-supplied system administration
documentation for more details.

The next attribute (if=) specified is the input filter.  More on this
later, but for now suffice it to say that this is the command that will
be presented with the print job data as it's standard input and is
responsible for printing that data and that there must be at least one
of these per printer.

The third attribute (sh) tells the spooler to suppress the generation
of header pages.  We need to do this because of the automatic detection
of PostScript source that if.sh does.  As a result, we must generate a
header page in the input filter.

The next attribute (sd=) specifies the spool directory.  By convention
we use the same name for this directory as the printer name.  This is
where all spooled requests are stored until they're printed.

The next attribute (lp=) may seem a bit odd.  Why specify a printer
device if the printer is attached to a terminal?  The reason is that
the spooler uses this file to do locking.  Normally this would be a
device special file, but all we need is a regular file.  If this file
is shared with other printer entries in the printcap file, each printer
will be used in turn -- i.e., they will take turns locking the file.

Another useful attribute when using HP printers is the pw (page width)
attribute.  The supplied input filter will adjust the page orientation
for HP printers based on page width -- if 80 or less portrait mode is
used; otherwise landscape mode is used.  The default page width is 132,
so make sure the printcap entry has a pw#80 attribute in it if you want
portrait mode output.


Input Filters

The input filter's job is to take the print job as input and get it
printed on the printer.  If the job appears to be PostScript (see the
next section for details) it will try to make sure the printer is a
PostScript printer.  It will provide a banner page with the user name,
host name from which the request originated, and the date and time.  It
will attempt to order the banner page and job pages correctly.  See the
section on printer types for more details.

The sample input filter supplied is called if.sh.  As it's name implies
it's a shell script.  The reason we made this part of the code a shell
script is that it's meant to server as an example -- it's not really
meant to solve all of the problems of spooling to a printer attached to
and NCD terminal.  At NCD, we do find that it works well enough that we
use it for all of our spooled printers.

From the point of view of the sample input filter, one of the problems
with the BSD spooler is that it can't be passed an argument to tell it
what NCD X terminal has the printer attached.  We solved this problem
by creating hard links to the shell script if.sh for each printer.  The
form of the name is:

	if%type%name

where type is the printer type (more on this later) and name is the
hostname (from /etc/hosts) or address of the terminal.

So the example printcap file had the input filter as:

	/usr/local/bin/ncdprint/if%lwup%ncdu145

This tells the input filter that the printer is an Apple LaserWriter
using the upper paper stacker and it's connected to ncdu145.

The utilities add_prt and del_prt are provided to assist in maintaining
these links.  Add_prt can be used to create the links and del_prt to
remove them.  For example, to add a new LaserWriter (type=lw) printer
on ncdu20:

    add_prt lw ncdu20

And likewise to remove the link use del_prt.  For example, if changing
to a LaserJet printer:

    del_prt lw ncdu20
    add_prt lj ncdu20

Normally, add_prt and del_prt will operate on links in
/usr/local/bin/ncdprint.  If you've installed the utilities elsewhere,
set the environment variable DESTBIN to the location of the binaries.
For example, for testing we use:

    setenv DESTBIN=testbin
    make install DESTBIN=$DESTBIN
    add_prt lw ncdu20

Once the printer has been installed, the NCD terminal configured, and
the printcap entry and it's related files and directories created you
can enable printing via the spooler using the lpc utility of the
spooler.  For example, for the printcap entry shown above for the
printer lablw, type:

    lpc restart lablw


PostScript or Not

The supplied input filter attempts to automatically recognize the
difference between PostScript and regular text data.  It does this by
looking at the first two characters of the data and if they are the
string "%!" it assumes PostScript source.

The reason only two characters are inspected is because we've found
several applications that simply use those two characters to identify
their PostScript output -- as opposed to %!PS or even more detailed
strings we've seen elsewhere.

Looking into the input stream and still getting those characters into
the output stream is tricky.  This is where the utility readn is used
in if.sh.  The reader of that script will also notice that the pipeline
of commands that actually sends the data to the printer also starts out
with a "cat -" command.  This is important.  If this is not done and
the input to if.sh is a "seek"able (as in seek(2)) source, the script
would fail.  The "cat -" command guarantees that the next stage of the
pipeline has input that is not "seek"able.


Printer Types

The sample input filter has support for four families of printers:
dumb ASCII printers, HP DeskJet printers, HP LaserJet printers, and
Apple LaserWriter printers.  The printer type used in the input filter
link name is matched as shown in the table below:

    ascii   any dump ASCII printer -- the only assumption is that FF
	    ejects the current page

    dj*     an HP DeskJet family printer (tested with 500)

    lj*     an HP LaserJet family printer (tested with IIP and III)

    lw*up   an Apple LaserWriter family printer using the top paper
            stacker (tested with LaserWriter, LaserWriter II, and
	    LaserWriter IINTX)

    lw*     an Apple LaserWriter family printer using the side paper
            stacker


So, for example, if%ljiii%ncdu20 is understood to be an HP LaserJet
family printer.


ASCII Printers

Any printer that prints ASCII characters and ejects the current page
when a FF is received should work.  The only testing we've done is to
use an HP LaserJet this way and see that it seems to work.

The banner page generated contains the user name, host name, and date
printed in block letters.

The input filter will exit abnormally if presented with PostScript
source.  Otherwise, it will simply order the banner page before the
text and send them to the printer.

Text files can have their lines folded at any column offset by
specifying a page width.  The filter doesn't do this if the width is
zero (0).


HP DeskJet Printers

Any of the HP DeskJet family printers should work.  At NCD we've tested
with a DeskJet 500 printer.

The banner page generated has a couple of grey bars to help it stand
out.  It just lists the user, host, and date between the bars.

The input filter sends this banner page and the text representing the
job to the printer.  It makes sure certain printer parameters are set
for each job by sending a reset sequence and then setting the
parameters it cares about.  You may find that you want to change
something here.  If so, just consult your HP printer Owner's or User's
manual and follow the example already in if.sh.

The page width will control whether pages are printed portrait or
landscape (the banner should always be portrait).  For page widths of
80 or less, the output will be portrait -- note that the spooler's
default is 132 which means unless you specify a pw# in the printcap
entry, you'll get landscape.  Landscape is slow on these printers, so
be careful.


HP LaserJet Printers

Any of the HP LaserJet family printers should work.  At NCD we've
tested with both LaserJet IIP and LaserJet III printers.

The banner page generated has a couple of 50% black bars to help it
stand out.  It just lists the user, host, and date between the bars.

The input filter sends this banner page and the text representing the
job to the printer.  It makes sure certain printer parameters are set
for each job by sending a reset sequence and then setting the
parameters it cares about.  You may find that you want to change
something here.  If so, just consult your HP printer Owner's or User's
manual and follow the example already in if.sh.

The page width will control whether pages are printed portrait or
landscape (the banner should always be portrait).  For page widths of
80 or less, the output will be portrait -- note that the spooler's
default is 132 which means unless you specify a pw# in the printcap
entry, you'll get landscape.


Apple LaserWriter Printers

Any of the Apple LaserWriter family printers that process PostScript
can be used.  At NCD we use LaserWriter II and LaserWriter II NTX
printers.

The banner page generated is a PostScript program that displays the
user name, host name, and date/time the request was printed as well as
the NCD and X logos.

The input filter attempts to convert text that is not PostScript source
to PostScript before it gets to the printer.  We use Barry Brachman's
lwf program.  As noted in the if.sh script (for historical reasons)
we've built it with page order reversal as the default.  If you use it
and don't build it this way, just change the definition of the
TXT_TO_PS and TXT_TO_PS_REV variables.

The order of the banner page and PostScript text is arranged to make
the banner page appear on the front of the job.  This is controlled by
the printer type.  Any printer type that matched lw*up is assumed to be
using the upper paper exit path and has the banner page printed first.
The upper exit works best when tools like troff are being used (unless
you have a smarter troff than we do -- ours won't reverse the pages).

Text files can have their lines folded at any column offset by
specifying a page width.  The filter doesn't do this if the width is
zero (0).  This is because some application's (e.g., spread sheets)
output does not fold well.  This can easily be controlled in the
printcap entry and overridden as needed on the lpr command line.

To set the line speed of an Apple LaserWriter IINTX to 38.4K baud,
after connecting the printer as outlined above, use the lw_maint
utility:

% lw_maint ncdu145
Printer LaserWriter II NTX has interface speed
currently set to 19200 baud with ignore parity.
What baud rate do you want? 38400
What kind of parity setting do you want? i
Enter printer password (try 0 if you haven't set one)? 0
91-02-12 23:42:46: ./ps2ncd: ncdu145: %%[ exitserver: permanent state may be changed ]%%


CREDIT

In an effort to give credit where credit's due, here goes:

The PostScript code for the X logo (xlogo.ps):

    Copyright (C) 1988 by Jef Poskanzer.

The banner program which has no copyright:

    Brian Wallis, brw@jim.odr.oz, 4 July 1988
