MH & nmh: Email for Users & Programmers

May, 2006

Changing the Print Command

The resource entry xmh*PrintCommand controls the way that xmh prints messages. This entry is the command line that you'd type at a Bourne shell prompt to print a file. When you select one or more messages and then select Print, xmh will start the print command and append the full pathnames of the messages. The following default print command:

    enscript >/dev/null 2>/dev/null
prints files on a PostScript printer (assuming you've installed Adobe System's enscript command).

For instance, let's say your MH directory is /xx/yy/Mail, your current folder is inbox, and you select messages 25 and 26 to print. When you choose Print, xmh will execute:

    enscript >/dev/null 2>/dev/null /xx/yy/Mail/inbox/25 /xx/yy/Mail/inbox/26
The command line above has the following problems:
  1. You might want to use some of the enscript options.
  2. You might not have the enscript command.
  3. You might not have, or want to use, a PostScript printer.
  4. Error messages are thrown away (into /dev/null, the UNIX "trash can").

Grabbing Error Output

The default printer command doesn't let you see printer errors; it just throws them away. If you don't get your output, it's nice to be able to see the error messages (if any). In xmh Release 5 and 6, printer messages on the standard error are put into a small window that pops up when there's a message. But the standard output of printer commands is thrown away unless you redirect it. (For some reason, on my version of UNIX, the lpr and lp commands write their errors to the standard output!) I've merged the standard output of my printer command onto the standard error so that any kind of printer message will be shown in the pop-up window. Here's what that looks like with the default enscript command:

    Xmh*PrintCommand: enscript 1>&2
For xmh Release 3 (or any release, actually), you can set your print command so that any output it makes goes to a file named .xmh_printerrs in your home directory. If you want to do that, here's an entry to use in your .Xdefaults file (replace the /xxx/yyy with the pathname of your home directory):
    xmh*PrintCommand: enscript >>/xxx/yyy/.xmh_printerrs 2>&1
The two right angle brackets (>>) mean that each new error is appended to the file. If you get a lot of printer errors, you'll want to clean out the file occasionally. Or, you can use one right angle bracket (>) instead -- that means that each time you use Print, any old errors will be overwritten (which could be good or bad). The 2>&1 means that all messages, from both the standard output and standard error, will go into the file (by itself, >> would only redirect standard output).

Printing with lpr and lp

To print on a line printer (which only handles text, not PostScript), try a command such as this on Berkeley-compatible systems which have the lpr(1) command:

    xmh*PrintCommand: lpr -p 1>&2
The -p formats your mail messages with the pr(1) command.

If your system has the System V lp command, which doesn't have a -p option, you should use this instead:

    xmh*PrintCommand: lp -s 1>&2
The -s option stops messages like request id is... But that command won't format your output with pr.

Other Printer Commands

If the printer you'll be using is different from the previous examples, you'll basically need to put everything but the filename into your xmh*PrintCommand. For example, if you type this command to print a file when you're not using xmh:

    % tcprint -Pwest -nolog filename
you'd put this entry in your .Xdefaults file:
    xmh*PrintCommand: tcprint -Pwest -nolog 1>&2
Unfortunately, you can't use a UNIX pipe (|) to print your files, such as pr myfile | lp. That's because xmh puts the filenames to print at the end of the command line, after the last command in the pipe.

To solve this, or to do other fancy things with mail printing, you'll need to write a little program that handles xmh printing. The program in the Section A Better xmh Printer: xmhprint is a good starting place.

A Better xmh Printer: xmhprint

As you've seen, the printer support with xmh isn't very good. It hands all of your message files to a printer command at once. It doesn't filter them to remove uninteresting header fields. You can't use a pipe as part of the printer command because xmh puts the message filenames at the end of the printer command line.

The xmhprint program is a simple shell script. It takes message filenames and any options from the command line. The shell script gets the message filenames from xmh, and it can process them any way you want it to. The options let you change your print setup easily -- instead of storing a complicated xmh*PrintCommand in the resource manager, just change the option on the command line.

By default, xmhprint gives your messages straight to the lpr command for printing. If you use its -p1 option, xmhprint will give your messages straight to pr and pipe the result to lpr. With the -p2 option, xmhprint puts each message's subject in the pr page heading before sending them to lpr. With what you know about shell programming, you can add your own xmhprint options to customize printing for your site and your needs. If you set environment variables before starting xmh, xmhprint can test its environment for them -- this gives you even more flexibility. Also, on Berkeley-type UNIX systems, you can set the PRINTER environment variable to the printer lpr will use. (On System V, set LPDEST.)

The script handles redirection of printer errors, too, so you don't need the >/dev/null 2>/dev/null business that the xmh manual page recommends. In fact, for xmh versions after Release 3, I don't agree with the manual page. If you use 2>/dev/null to throw away errors, you won't see the dialog boxes xmh pops up to show messages like printer disabled. Worse, some versions of lpr and lp put their error messages on the standard output instead of the standard error! xmh doesn't put standard output messages into a dialog box. The xmhprint script takes care of that by rerouting all printer stdout to stderr.

Using xmhprint, here's how uncomplicated your printing resource entry can be:

    xmh*PrintCommand: xmhprint -p2
The program is described in the Section Explanation of xmhprint.