Adding a printer to the system using CAP

Condition: You have a new AppleTalk or EtherTalk printer you want to hook up

  1. Make sure you can connect it.

    Printers might be connected through a serial port to a host computer. This procedure doesn't cover that case because Sun system documentation covers it adqeuately. However, be aware that serial port connections are very slow as compared to network connections. High serial transmission rates might be 9600 baud or 55 kilobits/sec. On the other hand, AppleTalk runs at 230 kilobits/sec. While you can attach a priter to a serial port, you'll be waiting 4 times longer just to ship the data to the printer.

    Few printers (at least inexpensive ones) will comfortably hang on directly on an Ethernet, but many will work on AppleTalk. To bridge these systems, you need either a AppleTalk Ethernet bridge in the form of a Kinetics/Shiva FastPath or the now cheaper printer bridges for AppleTalk legacy hardware such as an Asante MicroPrint.

  2. Make sure you have CAP software available.

    CAP is the Columbia AppleTalk Protocol public domain software that will run on AppleTalk or EtherTalk systems. This is no longer under development, but provides stable access to all Apple systems I've yet encountered. If you're going to use CAP under EtherTalk, make sure you have it configured properly.

    Is the printer a PostScript printer or not? If it is, you can use the off-the-shelf code for papif that comes with CAP. If it isn't, you'll need code that will talk over the AppleTalk/EtherTalk network to the printer using PAP (Apple's Printer Access Protocol) to run the printer. Code to do this is available here, in the form of papif-nops, if you don't have something else to drive the printer over the network. Code papif-nops.c.

    At Bristol the CAP run-time code is in /usr/local/lib/cap (on the host called garnet, and the source tree is rooted at /usr/local/src/cap60.

  3. Connect the printer to the network.

    Plug it in and use atlook to discover its name. atlook will spew out all the devices on the network. You'll have to wade through the output to locate the printer. If it is a real PostScript printer, it will have a name like some name:LaserWriter@* The name is everything before the colon, and the type of the printer is everything after it up to the @. If you know in advance it is a PostScript printer, you can save yourself some effort by using atlooklws which will filter out everything except the PostScript printers.

  4. Add the printer to cap.printers.

    cap.printers is a file that converts between printers that Unix knows about and that the AppleTalk/EtherTalk know about. This is a file that associates the Unix printer name and the network printer name. Dream up a Unix printer name for your new bit of kit and put it in the file along with the network name - complete with the name and type.

    At this point, CAP is ready to use the printer.

  5. Create a Unix spool directory for the new printer.

    The spool directory will contain temporary copies of the data destined for the printer. One of these must exist on every machine that intends using the printer, so if you have a lot of machines, you have to do this on each one (or use rdist to spray the new directory throughout your cluster of machines).

    The traditional place for spool directories is in /usr/spool/lpd so make a new directory here. Make sure the directory is permissioned rwx to both root and daemon, and rx to everybody else.

    On the host running CAP only, also create a log file in the printer's spool directory for CAP to use when printing (because it helps sort out problems when the printer or network malfunctions). This file should be something ending with -log, like deskjet-log so that users can find it and look inside when anything goes wrong with their jobs.

    On the host running CAP only, create a file called .banner in the printer's spool directory, and permission it rwx to both root and daemon and r to everybody else. If you don't get daemon's permissions right, the printer won't do anything and your system will spin its wheels trying to print to the printer forever.

  6. Create a /etc/printcap entry for the new printer.

    /etc/printcap contains all the information the Unix spooling system needs to know to route files to the printer. It has an arcane but forgiving format (see man printcap for details). You need to put the Unix name of the printer here - the one you associated with the printer in cap.printers, above - plus spool directory information, plus routing information in it.

    On the host running CAP only, the entry is more involved because you have to tell the spooling system how to print to the printer. The other hosts only need to be told which system has the printer attached to it (or equivalently, will use CAP to send files to it).

    On the host running CAP only, the entry will look like this: pname|PostScript|postscript|flowing prose printer description:\ :lp=/usr/spool/lpd/sdir/pname:sd=/usr/spool/lpd/sdir:\ :lf=/usr/spool/lpd/sdir/pname-log:af=/usr/adm/pname.acct:\ :if=/usr/local/lib/cap/if-filter:\ :of=/usr/local/lib/cap/of-filter:gf=/usr/local/lib/cap/atgf:\ :nf=/usr/local/lib/cap/atnf:tf=/usr/local/lib/cap/attf:\ :rf=/usr/local/lib/cap/atrf:vf=/usr/local/lib/cap/atvf:\ :cf=/usr/local/lib/cap/atcf:df=/usr/local/lib/cap/atdf:
    Replace all instances of pname in the above with your chosen Unix printer name. Replace all instances of sdir with the name of the spool directory you chose (hopefully in the directory /usr/spool/lpd as suggested before, or modify the entries accordingly). The of=, gf=, nf=, tf=, rf=, vf=, cf=, and df= entries are all standard boilerplate for CAP. If your printer is PostScript, you'll need to replace if=if-filter with if=atif and of=of-filter with of=atof. If not PostScript, replace if=if-filter with if=atif-nops and of=of-filter with either of=atof or a filter of your own choosing that will generate printer initialization code and/or a banner page file to be sent to the printer. papif-nops needs to be explicitly told about a banner file, so if you don't plan to use one don't worry about getting this right. Also update your printer description (the flowing prose part) to describe the printer to humans, e.g. "The DeskJet in Room G5" or "Sophie's Choice" or whatever.

    On hosts not running CAP, the entry, much simpler, will look like this: pname|PostScript|postscript|flowing prose printer description:\ :lp=:rp=pname:rm=host:\ :sd=/usr/spool/lpd/sdir:\ :lf=/usr/spool/lpd/sdir/pname-log:
    Replace all instances of pname in the above with your chosen Unix printer name. Replace all instances of sdir with the name of the spool directory you chose (hopefully in the directory /usr/spool/lpd as suggested before, or modify the entries accordingly). Finally, replace host with the name of the Unix host that is running CAP to talk to the printer. That's how your system knows where to ship off the data for the printer.

    Remember to add the same /etc/printcap entry to the other systems.

  7. Test.

    Try issuing the command lpq -Ppname from every machine. If your /etc/printcap isn't set up right, you'll get errors reported at this point. If there aren't any, next try issuing
    echo "Hello from `hostname`" | lpr -Ppname

    from all the hosts to make sure that the output gets to the printer.

  8. Customize.

    A typical customization is to write an intelligent input filter that detects alternate-format (or outright aberrant) input and acts accordingly. For example, a DeskJet printer might well have PostScript output directed at it. If so, it should run Ghostscript gs (the PostScript interpreter) to reformat the output to HP PCL that the DeskJet understands. You can do this by substituting a program or a shell script for the if= /etc/printcap entry. Bristol runs its DeskJet with special input and output filters. The output filter djof emits printer reset commands at the beginning of each job in case the previous one left the printer in an unusual state. This writes a file called .banner that the input filter (papif-nops) will prefix to the output destined for the printer. djof is,

    #  Output filter for a DeskJet/LaserJet printer.  This only emits a reset
    #  sequence so the printer isn't left in a bad state when the next job
    #  appears.
    touch $banner && [ ! -w $banner ] && echo "Can't open $banner" && exit 8
    sed -e 's/[     ]*%.*$//' -e 's/\\033/^[/g' << EOF | tr -d '\012' > $banner
    \033E\033&k2G                   %reset printer, set CR=CR,LF=CRLF,FF=CRFF */
    \033&l6d66p0o0e66f0L            %letter size, portrait, no perf skip */
    \0339                           %reset side margins */
    \033&a0r0C                      %move cursor to 0,0 */
    \033(0U                         %set US ascii font (ron@mlfarm) */
    kill -STOP $$

    Note the unusual termination style, suicide. Proper operation of the spooling system requires this.

    djif, the input filter, is a bit subtler. It detects incoming PostScript and runs Ghostscript on it, as follows:

    #  Input filter for a DeskJet/LaserJet printer.  This checks whether it is
    #  receiving PostScript and if so runs it through GhostScript to convert
    #  to DeskJet output.  Otherwise, it execs the normal input filter.
    read first_line
    first_two_chars=`expr "$first_line" : '\(..\)'`
    if [ "$first_two_chars" = "%!" ]; then
        #  It's PostScript; use Ghostscript to scan-convert and print it
        (echo $first_line && cat) |
        /usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=cdjcolor -r300x300 -sOutputF
    ile=- - |
        /usr/local/lib/cap/atif-nops $args && exit 0
        #  Plain text or HP/PCL, so just print it directly; print a form
        #  at the end to eject the last page.
        (echo $first_line && cat) | /usr/local/lib/cap/atif-nops $args && exit 0
    exit 2