Put in remaining pages and wiki contents.
[ikiwiki.git] / docs / handbook / handbook-printing-advanced.mdwn
1 \r
2 \r
3 ## 11.4 Advanced Printer Setup \r
4 \r
5 This section describes filters for printing specially formatted files, header pages, printing across networks, and restricting and accounting for printer usage.\r
6 \r
7 ### 11.4.1 Filters \r
8 \r
9 Although  **LPD**  handles network protocols, queuing, access control, and other aspects of printing, most of the ***real*** work happens in the ***filters***. Filters are programs that communicate with the printer and handle its device dependencies and special requirements. In the simple printer setup, we installed a plain text filter--an extremely simple one that should work with most printers (section [printing-intro-setup.html#PRINTING-TEXTFILTER Installing the Text Filter]).\r
10 \r
11 However, in order to take advantage of format conversion, printer accounting, specific printer quirks, and so on, you should understand how filters work. It will ultimately be the filter's responsibility to handle these aspects. And the bad news is that most of the time ***you*** have to provide filters yourself. The good news is that many are generally available; when they are not, they are usually easy to write.\r
12 \r
13 Also, DragonFly comes with one, `/usr/libexec/lpr/lpf`, that works with many printers that can print plain text. (It handles backspacing and tabs in the file, and does accounting, but that is about all it does.) There are also several filters and filter components in pkgsrc®.\r
14 \r
15 Here is what you will find in this section:\r
16 \r
18 * Section [printing-advanced.html#PRINTING-ADVANCED-FILTERS How Filters Work], tries to give an overview of a filter's role in the printing process. You should read this section to get an understanding of what is happening ***under the hood*** when  **LPD**  uses filters. This knowledge could help you anticipate and debug problems you might encounter as you install more and more filters on each of your printers.\r
20 *  **LPD**  expects every printer to be able to print plain text by default. This presents a problem for PostScript® (or other language-based printers) which cannot directly print plain text. Section [printing-advanced.html#PRINTING-ADVANCED-IF-CONVERSION Accommodating Plain Text Jobs on PostScript Printers] tells you what you should do to overcome this problem. You should read this section if you have a PostScript printer.\r
22 * PostScript is a popular output format for many programs. Even some people (myself included) write PostScript code directly. But PostScript printers are expensive. Section [printing-advanced.html#PRINTING-ADVANCED-PS Simulating PostScript on Non PostScript Printers] tells how you can further modify a printer's text filter to accept and print PostScript data on a ***non PostScript*** printer. You should read this section if you do not have a PostScript printer.\r
24 * Section [printing-advanced.html#PRINTING-ADVANCED-CONVFILTERS Conversion Filters] tells about a way you can automate the conversion of specific file formats, such as graphic or typesetting data, into formats your printer can understand. After reading this section, you should be able to set up your printers such that users can type `lpr -t` to print troff data, or `lpr -d` to print TeX DVI data, or `lpr -v` to print raster image data, and so forth. I recommend reading this section.\r
26 * Section [printing-advanced.html#PRINTING-ADVANCED-OF Output Filters] tells all about a not often used feature of  **LPD** : output filters. Unless you are printing header pages (see [printing-advanced.html#PRINTING-ADVANCED-HEADER-PAGES Header Pages]), you can probably skip that section altogether.\r
28 * Section [printing-advanced.html#PRINTING-ADVANCED-LPF lpf: a Text Filter] describes `lpf`, a fairly complete if simple text filter for line printers (and laser printers that act like line printers) that comes with DragonFly. If you need a quick way to get printer accounting working for plain text, or if you have a printer which emits smoke when it sees backspace characters, you should definitely consider `lpf`.\r
29 \r
30 #### How Filters Work \r
31 \r
32 As mentioned before, a filter is an executable program started by  **LPD**  to handle the device-dependent part of communicating with the printer.\r
33 \r
34 When  **LPD**  wants to print a file in a job, it starts a filter program. It sets the filter's standard input to the file to print, its standard output to the printer, and its standard error to the error logging file (specified in the `lf` capability in `/etc/printcap`, or `/dev/console` by default).\r
35 \r
36 Which filter  **LPD**  starts and the filter's arguments depend on what is listed in the `/etc/printcap` file and what arguments the user specified for the job on the [lpr(1)](http://leaf.dragonflybsd.org/cgi/web-man?command#lpr&section1) command line. For example, if the user typed `lpr -t`,  **LPD**  would start the troff filter, listed in the `tf` capability for the destination printer. If the user wanted to print plain text, it would start the `if` filter (this is mostly true: see [printing-advanced.html#PRINTING-ADVANCED-OF Output Filters] for details).\r
37 \r
38 There are three kinds of filters you can specify in `/etc/printcap`:\r
39 \r
41 * The ***text filter***, confusingly called the ***input filter*** in  **LPD**  documentation, handles regular text printing. Think of it as the default filter.  **LPD**  expects every printer to be able to print plain text by default, and it is the text filter's job to make sure backspaces, tabs, or other special characters do not confuse the printer. If you are in an environment where you have to account for printer usage, the text filter must also account for pages printed, usually by counting the number of lines printed and comparing that to the number of lines per page the printer supports. The text filter is started with the following argument list:\r
42   `filter-name` [-c] -w`***width***` -l`***length***` -i`***indent***` -n `***login***` -h `***host***` `***acct-file***`\r
43    where\r
44   `-c`:: appears if the job is submitted with `lpr -l******width***`:: is the value from the `pw` (page width) capability specified in `/etc/printcap`, default 132`***length***`:: is the value from the `pl` (page length) capability, default 66`***indent***`:: is the amount of the indentation from `lpr -i`, default 0`***login***`:: is the account name of the user printing the file`***host***`:: is the host name from which the job was submitted`***acct-file***`:: is the name of the accounting file from the `af` capability.\r
46 * A ***conversion filter*** converts a specific file format into one the printer can render onto paper. For example, ditroff typesetting data cannot be directly printed, but you can install a conversion filter for ditroff files to convert the ditroff data into a form the printer can digest and print. Section [printing-advanced.html#PRINTING-ADVANCED-CONVFILTERS Conversion Filters] tells all about them. Conversion filters also need to do accounting, if you need printer accounting. Conversion filters are started with the following arguments:\r
47   `filter-name` -x`***pixel-width***` -y`***pixel-height***` -n `***login***` -h `***host***` `***acct-file***`\r
48    where `***pixel-width***` is the value from the `px` capability (default 0) and `***pixel-height***` is the value from the `py` capability (default 0).\r
50 * The ***output filter*** is used only if there is no text filter, or if header pages are enabled. In my experience, output filters are rarely used. Section [printing-advanced.html#PRINTING-ADVANCED-OF Output Filters] describe them. There are only two arguments to an output filter:\r
51   `filter-name` -w`***width***` -l`***length***`\r
52    which are identical to the text filters `-w` and `-l` arguments.\r
53 \r
54 Filters should also ***exit*** with the following exit status:\r
55 \r
56 exit 0:: If the filter printed the file successfully.exit 1:: If the filter failed to print the file but wants  **LPD**  to try to print the file again.  **LPD**  will restart a filter if it exits with this status.exit 2:: If the filter failed to print the file and does not want  **LPD**  to try again.  **LPD**  will throw out the file.\r
57 \r
58 The text filter that comes with the DragonFly release, `/usr/libexec/lpr/lpf`, takes advantage of the page width and length arguments to determine when to send a form feed and how to account for printer usage. It uses the login, host, and accounting file arguments to make the accounting entries.\r
59 \r
60 If you are shopping for filters, see if they are LPD-compatible. If they are, they must support the argument lists described above. If you plan on writing filters for general use, then have them support the same argument lists and exit codes.\r
61 \r
62 #### Accommodating Plain Text Jobs on PostScript® Printers \r
63 \r
64 If you are the only user of your computer and PostScript (or other language-based) printer, and you promise to never send plain text to your printer and to never use features of various programs that will want to send plain text to your printer, then you do not need to worry about this section at all.\r
65 \r
66 But, if you would like to send both PostScript and plain text jobs to the printer, then you are urged to augment your printer setup. To do so, we have the text filter detect if the arriving job is plain text or PostScript. All PostScript jobs must start with `%!` (for other printer languages, see your printer documentation). If those are the first two characters in the job, we have PostScript, and can pass the rest of the job directly. If those are not the first two characters in the file, then the filter will convert the text into PostScript and print the result.\r
67 \r
68 How do we do this?\r
69 \r
70 #### Simulating PostScript on Non PostScript Printers \r
71 \r
72 PostScript is the ***de facto*** standard for high quality typesetting and printing. PostScript is, however, an ***expensive*** standard. Thankfully, Aladdin Enterprises has a free PostScript work-alike called  **Ghostscript**  that runs with DragonFly. Ghostscript can read most PostScript files and can render their pages onto a variety of devices, including many brands of non-PostScript printers. By installing Ghostscript and using a special text filter for your printer, you can make your non PostScript printer act like a real PostScript printer.\r
73 \r
74 Ghostscript is in pkgsrc, if you would like to install it from there. You can fetch, build, and install it quite easily yourself, as well.\r
75 \r
76 To simulate PostScript, we have the text filter detect if it is printing a PostScript file. If it is not, then the filter will pass the file directly to the printer; otherwise, it will use Ghostscript to first convert the file into a format the printer will understand.\r
77 \r
78 Here is an example: the following script is a text filter for Hewlett Packard DeskJet 500 printers. For other printers, substitute the `-sDEVICE` argument to the `gs` (Ghostscript) command. (Type `gs -h` to get a list of devices the current installation of Ghostscript supports.)\r
79 \r
80     \r
81     #!/bin/sh\r
82     #\r
83     #  ifhp - Print Ghostscript-simulated PostScript on a DeskJet 500\r
84     #  Installed in /usr/local/libexec/ifhp\r
85     \r
86     #\r
87     #  Treat LF as CR+LF:\r
88     #\r
89     printf "\033&k2G" || exit 2\r
90     \r
91     #\r
92     #  Read first two characters of the file\r
93     #\r
94     IFS="" read -r first_line\r
95     first_two_chars=`expr "$first_line" : '\(..\)'`\r
96     \r
97     if [ "$first_two_chars" = "%!" ]; then\r
98         #\r
99         #  It is PostScript; use Ghostscript to scan-convert and print it.\r
100         #\r
101         #  Note that PostScript files are actually interpreted programs,\r
102         #  and those programs are allowed to write to stdout, which will\r
103         #  mess up the printed output.  So, we redirect stdout to stderr\r
104         #  and then make descriptor 3 go to stdout, and have Ghostscript\r
105         #  write its output there.  Exercise for the clever reader:\r
106         #  capture the stderr output from Ghostscript and mail it back to\r
107         #  the user originating the print job.\r
108         #\r
109         exec 3>&1 1>&2\r
110         /usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 \\r
111             -sOutputFile=/dev/fd/3 - && exit 0\r
112     else\r
113         #\r
114         #  Plain text or HP/PCL, so just print it directly; print a form feed\r
115         #  at the end to eject the last page.\r
116         #\r
117         echo "$first_line" && cat && printf "\033&l0H" &&\r
118     exit 0\r
119     fi\r
120     \r
121     exit 2\r
122 \r
123 \r
124 Finally, you need to notify  **LPD**  of the filter via the `if` capability:\r
125 \r
126     \r
127     :if=/usr/local/libexec/ifhp:\r
128 \r
129 \r
130 That is it. You can type `lpr plain.text` and `lpr whatever.ps` and both should print successfully.\r
131 \r
132 #### Conversion Filters \r
133 \r
134 After completing the simple setup described in [printing-intro-setup.html#PRINTING-SIMPLE Simple Printer Setup], the first thing you will probably want to do is install conversion filters for your favorite file formats (besides plain ASCII text).\r
135 \r
136 ##### Why Install Conversion Filters? \r
137 \r
138 Conversion filters make printing various kinds of files easy. As an example, suppose we do a lot of work with the TeX typesetting system, and we have a PostScript printer. Every time we generate a DVI file from TeX, we cannot print it directly until we convert the DVI file into PostScript. The command sequence goes like this:\r
139 \r
140     \r
141     % dvips seaweed-analysis.dvi\r
142     % lpr seaweed-analysis.ps\r
143 \r
144 \r
145 By installing a conversion filter for DVI files, we can skip the hand conversion step each time by having  **LPD**  do it for us. Now, each time we get a DVI file, we are just one step away from printing it:\r
146 \r
147     \r
148     % lpr -d seaweed-analysis.dvi\r
149 \r
150 \r
151 We got  **LPD**  to do the DVI file conversion for us by specifying the `-d` option. Section [printing-using.html#PRINTING-LPR-OPTIONS-FORMAT Formatting and Conversion Options] lists the conversion options.\r
152 \r
153 For each of the conversion options you want a printer to support, install a ***conversion filter*** and specify its pathname in `/etc/printcap`. A conversion filter is like the text filter for the simple printer setup (see section [printing-intro-setup.html#PRINTING-TEXTFILTER Installing the Text Filter]) except that instead of printing plain text, the filter converts the file into a format the printer can understand.\r
154 \r
155 ##### Which Conversions Filters Should I Install? \r
156 \r
157 You should install the conversion filters you expect to use. If you print a lot of DVI data, then a DVI conversion filter is in order. If you have got plenty of troff to print out, then you probably want a troff filter.\r
158 \r
159 The following table summarizes the filters that  **LPD**  works with, their capability entries for the `/etc/printcap` file, and how to invoke them with the `lpr` command:\r
160 \r
161 [[!table  data="""
162 | File type | `/etc/printcap` capability | `lpr` option 
163  cifplot | `cf` | `-c` 
164  DVI | `df` | `-d` 
165  plot | `gf` | `-g` 
166  ditroff | `nf` | `-n` 
167  FORTRAN text | `rf` | `-f` 
168  troff | `tf` | `-f` 
169  raster | `vf` | `-v` 
170  plain text | `if` | none, `-p`, or `-l` |\r
171 """]]\r
172 In our example, using `lpr -d` means the printer needs a `df` capability in its entry in `/etc/printcap`.\r
173 \r
174 Despite what others might contend, formats like FORTRAN text and plot are probably obsolete. At your site, you can give new meanings to these or any of the formatting options just by installing custom filters. For example, suppose you would like to directly print Printerleaf files (files from the Interleaf desktop publishing program), but will never print plot files. You could install a Printerleaf conversion filter under the `gf` capability and then educate your users that `lpr -g` mean ***print Printerleaf files.***\r
175 \r
176 ##### Installing Conversion Filters \r
177 \r
178 Since conversion filters are programs you install outside of the base DragonFly installation, they should probably go under `/usr/local`. The directory `/usr/local/libexec` is a popular location, since they are specialized programs that only  **LPD**  will run; regular users should not ever need to run them.\r
179 \r
180 To enable a conversion filter, specify its pathname under the appropriate capability for the destination printer in `/etc/printcap`.\r
181 \r
182 In our example, we will add the DVI conversion filter to the entry for the printer named `bamboo`. Here is the example `/etc/printcap` file again, with the new `df` capability for the printer `bamboo`.\r
183 \r
184     \r
185     #\r
186     #  /etc/printcap for host rose - added df filter for bamboo\r
187     #\r
188     rattan|line|diablo|lp|Diablo 630 Line Printer:\\r
189             :sh:sd=/var/spool/lpd/rattan:\\r
190             :lp=/dev/lpt0:\\r
191             :if=/usr/local/libexec/if-simple:\r
192     \r
193     bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\\r
194             :sh:sd=/var/spool/lpd/bamboo:\\r
195             :lp=/dev/ttyd5:ms#-parenb cs8 clocal crtscts:rw:\\r
196             :if=/usr/local/libexec/psif:\\r
197             :df=/usr/local/libexec/psdf:\r
198 \r
199 \r
200 The DVI filter is a shell script named `/usr/local/libexec/psdf`. Here is that script:\r
201 \r
202     \r
203     #!/bin/sh\r
204     #\r
205     #  psdf - DVI to PostScript printer filter\r
206     #  Installed in /usr/local/libexec/psdf\r
207     #\r
208     # Invoked by lpd when user runs lpr -d\r
209     #\r
210     exec /usr/local/bin/dvips -f | /usr/local/libexec/lprps "$@"\r
211 \r
212 \r
213 This script runs `dvips` in filter mode (the `-f` argument) on standard input, which is the job to print. It then starts the PostScript printer filter `lprps` (see section [printing-advanced.html#PRINTING-ADVANCED-IF-CONVERSION Accommodating Plain Text Jobs on PostScript Printers]) with the arguments  **LPD**  passed to this script. `lprps` will use those arguments to account for the pages printed.\r
214 \r
215 ##### More Conversion Filter Examples \r
216 \r
217 Since there is no fixed set of steps to install conversion filters, let me instead provide more examples. Use these as guidance to making your own filters. Use them directly, if appropriate.\r
218 \r
219 This example script is a raster (well, GIF file, actually) conversion filter for a Hewlett Packard LaserJet III-Si printer:\r
220 \r
221     \r
222     #!/bin/sh\r
223     #\r
224     #  hpvf - Convert GIF files into HP/PCL, then print\r
225     #  Installed in /usr/local/libexec/hpvf\r
226     \r
227     PATH=/usr/X11R6/bin:$PATH; export PATH\r
228     giftopnm | ppmtopgm | pgmtopbm | pbmtolj -resolution 300 \\r
229         && exit 0 \\r
230         || exit 2\r
231 \r
232 \r
233 It works by converting the GIF file into a portable anymap, converting that into a portable graymap, converting that into a portable bitmap, and converting that into LaserJet/PCL-compatible data.\r
234 \r
235 Here is the `/etc/printcap` file with an entry for a printer using the above filter:\r
236 \r
237     \r
238     #\r
239     #  /etc/printcap for host orchid\r
240     #\r
241     teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\\r
242             :lp#/dev/lpt0:sh:sd/var/spool/lpd/teak:mx#0:\\r
243             :if=/usr/local/libexec/hpif:\\r
244             :vf=/usr/local/libexec/hpvf:\r
245 \r
246 \r
247 The following script is a conversion filter for troff data from the groff typesetting system for the PostScript printer named `bamboo`:\r
248 \r
249     \r
250     #!/bin/sh\r
251     #\r
252     #  pstf - Convert groff's troff data into PS, then print.\r
253     #  Installed in /usr/local/libexec/pstf\r
254     #\r
255     exec grops | /usr/local/libexec/lprps "$@"\r
256 \r
257 \r
258 The above script makes use of `lprps` again to handle the communication with the printer. If the printer were on a parallel port, we would use this script instead:\r
259 \r
260     \r
261     #!/bin/sh\r
262     #\r
263     #  pstf - Convert groff's troff data into PS, then print.\r
264     #  Installed in /usr/local/libexec/pstf\r
265     #\r
266     exec grops\r
267 \r
268 \r
269 That is it. Here is the entry we need to add to `/etc/printcap` to enable the filter:\r
270 \r
271     \r
272     :tf=/usr/local/libexec/pstf:\r
273 \r
274 \r
275 Here is an example that might make old hands at FORTRAN blush. It is a FORTRAN-text filter for any printer that can directly print plain text. We will install it for the printer `teak`:\r
276 \r
277     \r
278     #!/bin/sh\r
279     #\r
280     # hprf - FORTRAN text filter for LaserJet 3si:\r
281     # Installed in /usr/local/libexec/hprf\r
282     #\r
283     \r
284     printf "\033&k2G" && fpr && printf "\033&l0H" &&\r
285      exit 0\r
286     exit 2\r
287 \r
288 \r
289 And we will add this line to the `/etc/printcap` for the printer `teak` to enable this filter:\r
290 \r
291     \r
292     :rf=/usr/local/libexec/hprf:\r
293 \r
294 \r
295 ##### Automated Conversion: an Alternative to Conversion Filters \r
296 \r
297 All these conversion filters accomplish a lot for your printing environment, but at the cost forcing the user to specify (on the [lpr(1)](http://leaf.dragonflybsd.org/cgi/web-man?command#lpr&section1) command line) which one to use. If your users are not particularly computer literate, having to specify a filter option will become annoying. What is worse, though, is that an incorrectly specified filter option may run a filter on the wrong type of file and cause your printer to spew out hundreds of sheets of paper.\r
298 \r
299 Rather than install conversion filters at all, you might want to try having the text filter (since it is the default filter) detect the type of file it has been asked to print and then automatically run the right conversion filter. Tools such as `file` can be of help here. Of course, it will be hard to determine the differences between ***some*** file types--and, of course, you can still provide conversion filters just for them.\r
300 \r
301 The pkgsrc collection has a text filter that performs automatic conversion called `apsfilter`. It can detect plain text, PostScript, and DVI files, run the proper conversions, and print.\r
302 \r
303 #### Output Filters \r
304 \r
305 The  **LPD**  spooling system supports one other type of filter that we have not yet explored: an output filter. An output filter is intended for printing plain text only, like the text filter, but with many simplifications. If you are using an output filter but no text filter, then:\r
306 \r
308 *  **LPD**  starts an output filter once for the entire job instead of once for each file in the job.\r
310 *  **LPD**  does not make any provision to identify the start or the end of files within the job for the output filter.\r
312 *  **LPD**  does not pass the user's login or host to the filter, so it is not intended to do accounting. In fact, it gets only two arguments:\r
313   `filter-name` -w`***width***` -l`***length***`\r
314   Where `***width***` is from the `pw` capability and `***length***` is from the `pl` capability for the printer in question.\r
315 \r
316 Do not be seduced by an output filter's simplicity. If you would like each file in a job to start on a different page an output filter ***will not work***. Use a text filter (also known as an input filter); see section [printing-intro-setup.html#PRINTING-TEXTFILTER Installing the Text Filter]. Furthermore, an output filter is actually ***more complex*** in that it has to examine the byte stream being sent to it for special flag characters and must send signals to itself on behalf of  **LPD** .\r
317 \r
318 However, an output filter is ***necessary*** if you want header pages and need to send escape sequences or other initialization strings to be able to print the header page. (But it is also ***futile*** if you want to charge header pages to the requesting user's account, since  **LPD**  does not give any user or host information to the output filter.)\r
319 \r
320 On a single printer,  **LPD**  allows both an output filter and text or other filters. In such cases,  **LPD**  will start the output filter to print the header page (see section [printing-advanced.html#PRINTING-ADVANCED-HEADER-PAGES Header Pages]) only.  **LPD**  then expects the output filter to ***stop itself*** by sending two bytes to the filter: ASCII 031 followed by ASCII 001. When an output filter sees these two bytes (031, 001), it should stop by sending `SIGSTOP` to itself. When  **LPD** 's done running other filters, it will restart the output filter by sending `SIGCONT` to it.\r
321 \r
322 If there is an output filter but ***no*** text filter and  **LPD**  is working on a plain text job,  **LPD**  uses the output filter to do the job. As stated before, the output filter will print each file of the job in sequence with no intervening form feeds or other paper advancement, and this is probably ***not*** what you want. In almost all cases, you need a text filter.\r
323 \r
324 The program `lpf`, which we introduced earlier as a text filter, can also run as an output filter. If you need a quick-and-dirty output filter but do not want to write the byte detection and signal sending code, try `lpf`. You can also wrap `lpf` in a shell script to handle any initialization codes the printer might require.\r
325 \r
326 #### `lpf`: a Text Filter \r
327 \r
328 The program `/usr/libexec/lpr/lpf` that comes with DragonFly is a text filter (input filter) that can indent output (job submitted with `lpr -i`), allow literal characters to pass (job submitted with `lpr -l`), adjust the printing position for backspaces and tabs in the job, and account for pages printed. It can also act like an output filter.\r
329 \r
330 `lpf` is suitable for many printing environments. And although it has no capability to send initialization sequences to a printer, it is easy to write a shell script to do the needed initialization and then execute `lpf`.\r
331 \r
332 In order for `lpf` to do page accounting correctly, it needs correct values filled in for the `pw` and `pl` capabilities in the `/etc/printcap` file. It uses these values to determine how much text can fit on a page and how many pages were in a user's job. For more information on printer accounting, see [printing-advanced.html#PRINTING-ADVANCED-ACCT Accounting for Printer Usage].\r
333 \r
334 ### 11.4.2 Header Pages \r
335 \r
336 If you have ***lots*** of users, all of them using various printers, then you probably want to consider ***header pages*** as a necessary evil.\r
337 \r
338 Header pages, also known as ***banner*** or ***burst pages*** identify to whom jobs belong after they are printed. They are usually printed in large, bold letters, perhaps with decorative borders, so that in a stack of printouts they stand out from the real documents that comprise users' jobs. They enable users to locate their jobs quickly. The obvious drawback to a header page is that it is yet one more sheet that has to be printed for every job, their ephemeral usefulness lasting not more than a few minutes, ultimately finding themselves in a recycling bin or rubbish heap. (Note that header pages go with each job, not each file in a job, so the paper waste might not be that bad.)\r
339 \r
340 The  **LPD**  system can provide header pages automatically for your printouts ***if*** your printer can directly print plain text. If you have a PostScript printer, you will need an external program to generate the header page; see [printing-advanced.html#PRINTING-ADVANCED-HEADER-PAGES-PS Header Pages on PostScript Printers].\r
341 \r
342 #### Enabling Header Pages \r
343 \r
344 In the [printing-intro-setup.html#PRINTING-SIMPLE Simple Printer Setup] section, we turned off header pages by specifying `sh` (meaning ***suppress header***) in the `/etc/printcap` file. To enable header pages for a printer, just remove the `sh` capability.\r
345 \r
346 Sounds too easy, right?\r
347 \r
348 You are right. You ***might*** have to provide an output filter to send initialization strings to the printer. Here is an example output filter for Hewlett Packard PCL-compatible printers:\r
349 \r
350     \r
351     #!/bin/sh\r
352     #\r
353     #  hpof - Output filter for Hewlett Packard PCL-compatible printers\r
354     #  Installed in /usr/local/libexec/hpof\r
355     \r
356     printf "\033&k2G" || exit 2\r
357     exec /usr/libexec/lpr/lpf\r
358 \r
359 \r
360 Specify the path to the output filter in the `of` capability. See the [printing-advanced.html#PRINTING-ADVANCED-OF Output Filters] section for more information.\r
361 \r
362 Here is an example `/etc/printcap` file for the printer `teak` that we introduced earlier; we enabled header pages and added the above output filter:\r
363 \r
364     \r
365     #\r
366     #  /etc/printcap for host orchid\r
367     #\r
368     teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\\r
369             :lp#/dev/lpt0:sd/var/spool/lpd/teak:mx#0:\\r
370             :if=/usr/local/libexec/hpif:\\r
371             :vf=/usr/local/libexec/hpvf:\\r
372             :of=/usr/local/libexec/hpof:\r
373 \r
374 \r
375 Now, when users print jobs to `teak`, they get a header page with each job. If users want to spend time searching for their printouts, they can suppress header pages by submitting the job with `lpr -h`; see the [printing-using.html#PRINTING-LPR-OPTIONS-MISC Header Page Options] section for more [lpr(1)](http://leaf.dragonflybsd.org/cgi/web-man?command#lpr&section1) options.\r
376 \r
377  **Note:**  **LPD**  prints a form feed character after the header page. If your printer uses a different character or sequence of characters to eject a page, specify them with the `ff` capability in `/etc/printcap`.\r
378 \r
379 #### Controlling Header Pages \r
380 \r
381 By enabling header pages,  **LPD**  will produce a ***long header***, a full page of large letters identifying the user, host, and job. Here is an example (kelly printed the job named outline from host `rose`):\r
382 \r
383     \r
384           k                   ll       ll\r
385           k                    l        l\r
386           k                    l        l\r
387           k   k     eeee       l        l     y    y\r
388           k  k     e    e      l        l     y    y\r
389           k k      eeeeee      l        l     y    y\r
390           kk k     e           l        l     y    y\r
391           k   k    e    e      l        l     y   yy\r
392           k    k    eeee      lll      lll     yyy y\r
393                                                    y\r
394                                               y    y\r
395                                                yyyy\r
396     \r
397                                        ll\r
398                               t         l        i\r
399                               t         l\r
400            oooo    u    u   ttttt       l       ii     n nnn     eeee\r
401           o    o   u    u     t         l        i     nn   n   e    e\r
402           o    o   u    u     t         l        i     n    n   eeeeee\r
403           o    o   u    u     t         l        i     n    n   e\r
404           o    o   u   uu     t  t      l        i     n    n   e    e\r
405            oooo     uuu u      tt      lll      iii    n    n    eeee\r
406     \r
407           r rrr     oooo     ssss     eeee\r
408           rr   r   o    o   s    s   e    e\r
409           r        o    o    ss      eeeeee\r
410           r        o    o      ss    e\r
411           r        o    o   s    s   e    e\r
412           r         oooo     ssss     eeee\r
413     \r
414                                                   Job:  outline\r
415                                                   Date: Sun Sep 17 11:04:58 1995\r
416 \r
417 \r
418  **LPD**  appends a form feed after this text so the job starts on a new page (unless you have `sf` (suppress form feeds) in the destination printer's entry in `/etc/printcap`).\r
419 \r
420 If you prefer,  **LPD**  can make a ***short header***; specify `sb` (short banner) in the `/etc/printcap` file. The header page will look like this:\r
421 \r
422     \r
423     rose:kelly  Job: outline  Date: Sun Sep 17 11:07:51 1995\r
424 \r
425 \r
426 Also by default,  **LPD**  prints the header page first, then the job. To reverse that, specify `hl` (header last) in `/etc/printcap`.\r
427 \r
428 #### Accounting for Header Pages \r
429 \r
430 Using  **LPD** 's built-in header pages enforces a particular paradigm when it comes to printer accounting: header pages must be ***free of charge***.\r
431 \r
432 Why?\r
433 \r
434 Because the output filter is the only external program that will have control when the header page is printed that could do accounting, and it is not provided with any ***user or host*** information or an accounting file, so it has no idea whom to charge for printer use. It is also not enough to just ***add one page*** to the text filter or any of the conversion filters (which do have user and host information) since users can suppress header pages with `lpr -h`. They could still be charged for header pages they did not print. Basically, `lpr -h` will be the preferred option of environmentally-minded users, but you cannot offer any incentive to use it.\r
435 \r
436 It is ***still not enough*** to have each of the filters generate their own header pages (thereby being able to charge for them). If users wanted the option of suppressing the header pages with `lpr -h`, they will still get them and be charged for them since  **LPD**  does not pass any knowledge of the `-h` option to any of the filters.\r
437 \r
438 So, what are your options?\r
439 \r
440 You can:\r
441 \r
443 * Accept  **LPD** 's paradigm and make header pages free.\r
445 * Install an alternative to  **LPD** , such as  **LPRng** . Section [printing-lpd-alternatives.html Alternatives to the Standard Spooler] tells more about other spooling software you can substitute for  **LPD** .\r
447 * Write a ***smart*** output filter. Normally, an output filter is not meant to do anything more than initialize a printer or do some simple character conversion. It is suited for header pages and plain text jobs (when there is no text (input) filter). But, if there is a text filter for the plain text jobs, then  **LPD**  will start the output filter only for the header pages. And the output filter can parse the header page text that  **LPD**  generates to determine what user and host to charge for the header page. The only other problem with this method is that the output filter still does not know what accounting file to use (it is not passed the name of the file from the `af` capability), but if you have a well-known accounting file, you can hard-code that into the output filter. To facilitate the parsing step, use the `sh` (short header) capability in `/etc/printcap`. Then again, all that might be too much trouble, and users will certainly appreciate the more generous system administrator who makes header pages free.\r
448 \r
449 #### Header Pages on PostScript Printers \r
450 \r
451 As described above,  **LPD**  can generate a plain text header page suitable for many printers. Of course, PostScript cannot directly print plain text, so the header page feature of  **LPD**  is useless--or mostly so.\r
452 \r
453 One obvious way to get header pages is to have every conversion filter and the text filter generate the header page. The filters should use the user and host arguments to generate a suitable header page. The drawback of this method is that users will always get a header page, even if they submit jobs with `lpr -h`.\r
454 \r
455 Let us explore this method. The following script takes three arguments (user login name, host name, and job name) and makes a simple PostScript header page:\r
456 \r
457     \r
458     #!/bin/sh\r
459     #\r
460     #  make-ps-header - make a PostScript header page on stdout\r
461     #  Installed in /usr/local/libexec/make-ps-header\r
462     #\r
463     \r
464     #\r
465     #  These are PostScript units (72 to the inch).  Modify for A4 or\r
466     #  whatever size paper you are using:\r
467     #\r
468     page_width=612\r
469     page_height=792\r
470     border=72\r
471     \r
472     #\r
473     #  Check arguments\r
474     #\r
475     if [ $# -ne 3 ]; then\r
476         echo "Usage: `basename $0` <user> <host> <job>" 1>&2\r
477         exit 1\r
478     fi\r
479     \r
480     #\r
481     #  Save these, mostly for readability in the PostScript, below.\r
482     #\r
483     user=$1\r
484     host=$2\r
485     job=$3\r
486     date=`date`\r
487     \r
488     #\r
489     #  Send the PostScript code to stdout.\r
490     #\r
491     exec cat <<EOF\r
492     %!PS\r
493     \r
494     %\r
495     %  Make sure we do not interfere with user's job that will follow\r
496     %\r
497     save\r
498     \r
499     %\r
500     %  Make a thick, unpleasant border around the edge of the paper.\r
501     %\r
502     $border $border moveto\r
503     $page_width $border 2 mul sub 0 rlineto\r
504     0 $page_height $border 2 mul sub rlineto\r
505     currentscreen 3 -1 roll pop 100 3 1 roll setscreen\r
506     $border 2 mul $page_width sub 0 rlineto closepath\r
507     0.8 setgray 10 setlinewidth stroke 0 setgray\r
508     \r
509     %\r
510     %  Display user's login name, nice and large and prominent\r
511     %\r
512     /Helvetica-Bold findfont 64 scalefont setfont\r
513     $page_width ($user) stringwidth pop sub 2 div $page_height 200 sub moveto\r
514     ($user) show\r
515     \r
516     %\r
517     %  Now show the boring particulars\r
518     %\r
519     /Helvetica findfont 14 scalefont setfont\r
520     /y 200 def\r
521     [ (Job:) (Host:) (Date:) ] {\r
522     200 y moveto show /y y 18 sub def }\r
523     forall\r
524     \r
525     /Helvetica-Bold findfont 14 scalefont setfont\r
526     /y 200 def\r
527     [ ($job) ($host) ($date) ] {\r
528             270 y moveto show /y y 18 sub def\r
529     } forall\r
530     \r
531     %\r
532     % That is it\r
533     %\r
534     restore\r
535     showpage\r
536     EOF\r
537 \r
538 \r
539 Now, each of the conversion filters and the text filter can call this script to first generate the header page, and then print the user's job. Here is the DVI conversion filter from earlier in this document, modified to make a header page:\r
540 \r
541     \r
542     #!/bin/sh\r
543     #\r
544     #  psdf - DVI to PostScript printer filter\r
545     #  Installed in /usr/local/libexec/psdf\r
546     #\r
547     #  Invoked by lpd when user runs lpr -d\r
548     #\r
549     \r
550     orig_args="$@"\r
551     \r
552     fail() {\r
553         echo "$@" 1>&2\r
554         exit 2\r
555     }\r
556     \r
557     while getopts "x:y:n:h:" option; do\r
558         case $option in\r
559             x|y)  ;; # Ignore\r
560             n)    login=$OPTARG ;;\r
561             h)    host=$OPTARG ;;\r
563 *)    echo "LPD started `basename $0` wrong." 1>&2\r
564                   exit 2\r
565                   ;;\r
566         esac\r
567     done\r
568     \r
569     [ "$login" ] || fail "No login name"\r
570     [ "$host" ] || fail "No host name"\r
571     \r
572     ( /usr/local/libexec/make-ps-header $login $host "DVI File"\r
573       /usr/local/bin/dvips -f ) | eval /usr/local/libexec/lprps $orig_args\r
574 \r
575 \r
576 Notice how the filter has to parse the argument list in order to determine the user and host name. The parsing for the other conversion filters is identical. The text filter takes a slightly different set of arguments, though (see section [printing-advanced.html#PRINTING-ADVANCED-FILTERS How Filters Work]).\r
577 \r
578 As we have mentioned before, the above scheme, though fairly simple, disables the ***suppress header page*** option (the `-h` option) to `lpr`. If users wanted to save a tree (or a few pennies, if you charge for header pages), they would not be able to do so, since every filter's going to print a header page with every job.\r
579 \r
580 To allow users to shut off header pages on a per-job basis, you will need to use the trick introduced in section [printing-advanced.html#PRINTING-ADVANCED-HEADER-PAGES-ACCOUNTING Accounting for Header Pages]: write an output filter that parses the LPD-generated header page and produces a PostScript version. If the user submits the job with `lpr -h`, then  **LPD**  will not generate a header page, and neither will your output filter. Otherwise, your output filter will read the text from  **LPD**  and send the appropriate header page PostScript code to the printer.\r
581 \r
582 If you have a PostScript printer on a serial line, you can make use of `lprps`, which comes with an output filter, `psof`, which does the above. Note that `psof` does not charge for header pages.\r
583 \r
584 ### 11.4.3 Networked Printing \r
585 \r
586 DragonFly supports networked printing: sending jobs to remote printers. Networked printing generally refers to two different things:\r
587 \r
589 * Accessing a printer attached to a remote host. You install a printer that has a conventional serial or parallel interface on one host. Then, you set up  **LPD**  to enable access to the printer from other hosts on the network. Section [printing-advanced.html#PRINTING-ADVANCED-NETWORK-RM Printers Installed on Remote Hosts] tells how to do this.\r
591 * Accessing a printer attached directly to a network. The printer has a network interface in addition (or in place of) a more conventional serial or parallel interface. Such a printer might work as follows:\r
593 * It might understand the  **LPD**  protocol and can even queue jobs from remote hosts. In this case, it acts just like a regular host running  **LPD** . Follow the same procedure in section [printing-advanced.html#PRINTING-ADVANCED-NETWORK-RM Printers Installed on Remote Hosts] to set up such a printer.\r
595 * It might support a data stream network connection. In this case, you ***attach*** the printer to one host on the network by making that host responsible for spooling jobs and sending them to the printer. Section [printing-advanced.html#PRINTING-ADVANCED-NETWORK-NET-IF Printers with Networked Data Stream Interfaces] gives some suggestions on installing such printers.\r
596 \r
597 #### Printers Installed on Remote Hosts \r
598 \r
599 The  **LPD**  spooling system has built-in support for sending jobs to other hosts also running  **LPD**  (or are compatible with  **LPD** ). This feature enables you to install a printer on one host and make it accessible from other hosts. It also works with printers that have network interfaces that understand the  **LPD**  protocol.\r
600 \r
601 To enable this kind of remote printing, first install a printer on one host, the ***printer host***, using the simple printer setup described in the [printing-intro-setup.html#PRINTING-SIMPLE Simple Printer Setup] section. Do any advanced setup in [printing-advanced.html Advanced Printer Setup] that you need. Make sure to test the printer and see if it works with the features of  **LPD**  you have enabled. Also ensure that the ***local host*** has authorization to use the  **LPD**  service in the ***remote host*** (see [printing-advanced.html#PRINTING-ADVANCED-RESTRICTING-REMOTE Restricting Jobs from Remote Printers]).\r
602 \r
603 If you are using a printer with a network interface that is compatible with  **LPD** , then the ***printer host*** in the discussion below is the printer itself, and the ***printer name*** is the name you configured for the printer. See the documentation that accompanied your printer and/or printer-network interface.\r
604 \r
605  **Tip:** If you are using a Hewlett Packard Laserjet then the printer name `text` will automatically perform the LF to CRLF conversion for you, so you will not require the `hpif` script.\r
606 \r
607 Then, on the other hosts you want to have access to the printer, make an entry in their `/etc/printcap` files with the following:\r
608 \r
609   1. Name the entry anything you want. For simplicity, though, you probably want to use the same name and aliases as on the printer host.\r
610   1. Leave the `lp` capability blank, explicitly (`:lp=:`).\r
611   1. Make a spooling directory and specify its location in the `sd` capability.  **LPD**  will store jobs here before they get sent to the printer host.\r
612   1. Place the name of the printer host in the `rm` capability.\r
613   1. Place the printer name on the ***printer host*** in the `rp` capability.\r
614 \r
615 That is it. You do not need to list conversion filters, page dimensions, or anything else in the `/etc/printcap` file.\r
616 \r
617 Here is an example. The host `rose` has two printers, `bamboo` and `rattan`. We will enable users on the host `orchid` to print to those printers. Here is the `/etc/printcap` file for `orchid` (back from section [printing-advanced.html#PRINTING-ADVANCED-HEADER-PAGES-ENABLING Enabling Header Pages]). It already had the entry for the printer `teak`; we have added entries for the two printers on the host `rose`:\r
618 \r
619     \r
620     #\r
621     #  /etc/printcap for host orchid - added (remote) printers on rose\r
622     #\r
623     \r
624     #\r
625     #  teak is local; it is connected directly to orchid:\r
626     #\r
627     teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\\r
628             :lp#/dev/lpt0:sd/var/spool/lpd/teak:mx#0:\\r
629             :if=/usr/local/libexec/ifhp:\\r
630             :vf=/usr/local/libexec/vfhp:\\r
631             :of=/usr/local/libexec/ofhp:\r
632     \r
633     #\r
634     #  rattan is connected to rose; send jobs for rattan to rose:\r
635     #\r
636     rattan|line|diablo|lp|Diablo 630 Line Printer:\\r
637             :lp#:rmrose:rp=rattan:sd=/var/spool/lpd/rattan:\r
638     \r
639     #\r
640     #  bamboo is connected to rose as well:\r
641     #\r
642     bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\\r
643             :lp#:rmrose:rp=bamboo:sd=/var/spool/lpd/bamboo:\r
644 \r
645 \r
646 Then, we just need to make spooling directories on `orchid`:\r
647 \r
648     \r
649     # mkdir -p /var/spool/lpd/rattan /var/spool/lpd/bamboo\r
650     # chmod 770 /var/spool/lpd/rattan /var/spool/lpd/bamboo\r
651     # chown daemon:daemon /var/spool/lpd/rattan /var/spool/lpd/bamboo\r
652 \r
653 \r
654 Now, users on `orchid` can print to `rattan` and `bamboo`. If, for example, a user on `orchid` typed\r
655 \r
656     \r
657     % lpr -P bamboo -d sushi-review.dvi\r
658 \r
659 \r
660  the  **LPD**  system on `orchid` would copy the job to the spooling directory `/var/spool/lpd/bamboo` and note that it was a DVI job. As soon as the host `rose` has room in its `bamboo` spooling directory, the two  **LPDs**  would transfer the file to `rose`. The file would wait in `rose`'s queue until it was finally printed. It would be converted from DVI to PostScript (since `bamboo` is a PostScript printer) on `rose`.\r
661 \r
662 #### Printers with Networked Data Stream Interfaces \r
663 \r
664 Often, when you buy a network interface card for a printer, you can get two versions: one which emulates a spooler (the more expensive version), or one which just lets you send data to it as if you were using a serial or parallel port (the cheaper version). This section tells how to use the cheaper version. For the more expensive one, see the previous section [printing-advanced.html#PRINTING-ADVANCED-NETWORK-RM Printers Installed on Remote Hosts].\r
665 \r
666 The format of the `/etc/printcap` file lets you specify what serial or parallel interface to use, and (if you are using a serial interface), what baud rate, whether to use flow control, delays for tabs, conversion of newlines, and more. But there is no way to specify a connection to a printer that is listening on a TCP/IP or other network port.\r
667 \r
668 To send data to a networked printer, you need to develop a communications program that can be called by the text and conversion filters. Here is one such example: the script `netprint` takes all data on standard input and sends it to a network-attached printer. We specify the hostname of the printer as the first argument and the port number to which to connect as the second argument to `netprint`. Note that this supports one-way communication only (DragonFly to printer); many network printers support two-way communication, and you might want to take advantage of that (to get printer status, perform accounting, etc.).\r
669 \r
670     \r
671     #!/usr/bin/perl\r
672     #\r
673     #  netprint - Text filter for printer attached to network\r
674     #  Installed in /usr/local/libexec/netprint\r
675     #\r
676     $#ARGV eq 1 || die "Usage: $0 <printer-hostname> <port-number>";\r
677     \r
678     $printer_host = $ARGV[0];\r
679     $printer_port = $ARGV[1];\r
680     \r
681     require 'sys/socket.ph';\r
682     \r
683     ($ignore, $ignore, $protocol) = getprotobyname('tcp');\r
684     ($ignore, $ignore, $ignore, $ignore, $address)\r
685         = gethostbyname($printer_host);\r
686     \r
687     $sockaddr = pack('S n a4 x8', &AF_INET, $printer_port, $address);\r
688     \r
689     socket(PRINTER, &PF_INET, &SOCK_STREAM, $protocol)\r
690         || die "Can't create TCP/IP stream socket: $!";\r
691     connect(PRINTER, $sockaddr) || die "Can't contact $printer_host: $!";\r
692     while (<STDIN>) { print PRINTER; }\r
693     exit 0;\r
694 \r
695 \r
696 We can then use this script in various filters. Suppose we had a Diablo 750-N line printer connected to the network. The printer accepts data to print on port number 5100. The host name of the printer is scrivener. Here is the text filter for the printer:\r
697 \r
698     \r
699     #!/bin/sh\r
700     #\r
701     #  diablo-if-net - Text filter for Diablo printer `scrivener' listening\r
702     #  on port 5100.   Installed in /usr/local/libexec/diablo-if-net\r
703     #\r
704     exec /usr/libexec/lpr/lpf "$@" | /usr/local/libexec/netprint scrivener 5100\r
705 \r
706 \r
707 ### 11.4.4 Restricting Printer Usage \r
708 \r
709 This section gives information on restricting printer usage. The  **LPD**  system lets you control who can access a printer, both locally or remotely, whether they can print multiple copies, how large their jobs can be, and how large the printer queues can get.\r
710 \r
711 #### Restricting Multiple Copies \r
712 \r
713 The  **LPD**  system makes it easy for users to print multiple copies of a file. Users can print jobs with `lpr -#5` (for example) and get five copies of each file in the job. Whether this is a good thing is up to you.\r
714 \r
715 If you feel multiple copies cause unnecessary wear and tear on your printers, you can disable the `-#` option to [lpr(1)](http://leaf.dragonflybsd.org/cgi/web-man?command#lpr&section1) by adding the `sc` capability to the `/etc/printcap` file. When users submit jobs with the `-#` option, they will see:\r
716 \r
717     \r
718     lpr: multiple copies are not allowed\r
719 \r
720 \r
721 Note that if you have set up access to a printer remotely (see section [printing-advanced.html#PRINTING-ADVANCED-NETWORK-RM Printers Installed on Remote Hosts]), you need the `sc` capability on the remote `/etc/printcap` files as well, or else users will still be able to submit multiple-copy jobs by using another host.\r
722 \r
723 Here is an example. This is the `/etc/printcap` file for the host `rose`. The printer `rattan` is quite hearty, so we will allow multiple copies, but the laser printer `bamboo` is a bit more delicate, so we will disable multiple copies by adding the `sc` capability:\r
724 \r
725     \r
726     #\r
727     #  /etc/printcap for host rose - restrict multiple copies on bamboo\r
728     #\r
729     rattan|line|diablo|lp|Diablo 630 Line Printer:\\r
730             :sh:sd=/var/spool/lpd/rattan:\\r
731             :lp=/dev/lpt0:\\r
732             :if=/usr/local/libexec/if-simple:\r
733     \r
734     bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\\r
735             :sh:sd=/var/spool/lpd/bamboo:sc:\\r
736             :lp=/dev/ttyd5:ms#-parenb cs8 clocal crtscts:rw:\\r
737             :if=/usr/local/libexec/psif:\\r
738             :df=/usr/local/libexec/psdf:\r
739 \r
740 \r
741 Now, we also need to add the `sc` capability on the host `orchid`'s `/etc/printcap` (and while we are at it, let us disable multiple copies for the printer `teak`):\r
742 \r
743     \r
744     #\r
745     #  /etc/printcap for host orchid - no multiple copies for local\r
746     #  printer teak or remote printer bamboo\r
747     teak|hp|laserjet|Hewlett Packard LaserJet 3Si:\\r
748             :lp#/dev/lpt0:sd/var/spool/lpd/teak:mx#0:sc:\\r
749             :if=/usr/local/libexec/ifhp:\\r
750             :vf=/usr/local/libexec/vfhp:\\r
751             :of=/usr/local/libexec/ofhp:\r
752     \r
753     rattan|line|diablo|lp|Diablo 630 Line Printer:\\r
754             :lp#:rmrose:rp=rattan:sd=/var/spool/lpd/rattan:\r
755     \r
756     bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\\r
757             :lp#:rmrose:rp=bamboo:sd=/var/spool/lpd/bamboo:sc:\r
758 \r
759 \r
760 By using the `sc` capability, we prevent the use of `lpr -#`, but that still does not prevent users from running [lpr(1)](http://leaf.dragonflybsd.org/cgi/web-man?command#lpr&section1) multiple times, or from submitting the same file multiple times in one job like this:\r
761 \r
762     \r
763     % lpr forsale.sign forsale.sign forsale.sign forsale.sign forsale.sign\r
764 \r
765 \r
766 There are many ways to prevent this abuse (including ignoring it) which you are free to explore.\r
767 \r
768 #### Restricting Access to Printers \r
769 \r
770 You can control who can print to what printers by using the UNIX® group mechanism and the `rg` capability in `/etc/printcap`. Just place the users you want to have access to a printer in a certain group, and then name that group in the `rg` capability.\r
771 \r
772 Users outside the group (including `root`) will be greeted with ***`lpr: Not a member of the restricted group`*** if they try to print to the controlled printer.\r
773 \r
774 As with the `sc` (suppress multiple copies) capability, you need to specify `rg` on remote hosts that also have access to your printers, if you feel it is appropriate (see section [printing-advanced.html#PRINTING-ADVANCED-NETWORK-RM Printers Installed on Remote Hosts]).\r
775 \r
776 For example, we will let anyone access the printer `rattan`, but only those in group `artists` can use `bamboo`. Here is the familiar `/etc/printcap` for host `rose`:\r
777 \r
778     \r
779     #\r
780     #  /etc/printcap for host rose - restricted group for bamboo\r
781     #\r
782     rattan|line|diablo|lp|Diablo 630 Line Printer:\\r
783             :sh:sd=/var/spool/lpd/rattan:\\r
784             :lp=/dev/lpt0:\\r
785             :if=/usr/local/libexec/if-simple:\r
786     \r
787     bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\\r
788             :sh:sd#/var/spool/lpd/bamboo:sc:rgartists:\\r
789             :lp=/dev/ttyd5:ms#-parenb cs8 clocal crtscts:rw:\\r
790             :if=/usr/local/libexec/psif:\\r
791             :df=/usr/local/libexec/psdf:\r
792 \r
793 \r
794 Let us leave the other example `/etc/printcap` file (for the host `orchid`) alone. Of course, anyone on `orchid` can print to `bamboo`. It might be the case that we only allow certain logins on `orchid` anyway, and want them to have access to the printer. Or not.\r
795 \r
796  **Note:** There can be only one restricted group per printer.\r
797 \r
798 #### Controlling Sizes of Jobs Submitted \r
799 \r
800 If you have many users accessing the printers, you probably need to put an upper limit on the sizes of the files users can submit to print. After all, there is only so much free space on the filesystem that houses the spooling directories, and you also need to make sure there is room for the jobs of other users.\r
801 \r
802  **LPD**  enables you to limit the maximum byte size a file in a job can be with the `mx` capability. The units are in `BUFSIZ` blocks, which are 1024 bytes. If you put a zero for this capability, there will be no limit on file size; however, if no `mx` capability is specified, then a default limit of 1000 blocks will be used.\r
803 \r
804  **Note:** The limit applies to ***files*** in a job, and ***not*** the total job size.\r
805 \r
806  **LPD**  will not refuse a file that is larger than the limit you place on a printer. Instead, it will queue as much of the file up to the limit, which will then get printed. The rest will be discarded. Whether this is correct behavior is up for debate.\r
807 \r
808 Let us add limits to our example printers `rattan` and `bamboo`. Since those artists' PostScript files tend to be large, we will limit them to five megabytes. We will put no limit on the plain text line printer:\r
809 \r
810     \r
811     #\r
812     #  /etc/printcap for host rose\r
813     #\r
814     \r
815     #\r
816     #  No limit on job size:\r
817     #\r
818     rattan|line|diablo|lp|Diablo 630 Line Printer:\\r
819             :sh:mx#0:sd=/var/spool/lpd/rattan:\\r
820             :lp=/dev/lpt0:\\r
821             :if=/usr/local/libexec/if-simple:\r
822     \r
823     #\r
824     #  Limit of five megabytes:\r
825     #\r
826     bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\\r
827             :sh:sd#/var/spool/lpd/bamboo:sc:rgartists:mx#5000:\\r
828             :lp=/dev/ttyd5:ms#-parenb cs8 clocal crtscts:rw:\\r
829             :if=/usr/local/libexec/psif:\\r
830             :df=/usr/local/libexec/psdf:\r
831 \r
832 \r
833 Again, the limits apply to the local users only. If you have set up access to your printers remotely, remote users will not get those limits. You will need to specify the `mx` capability in the remote `/etc/printcap` files as well. See section [printing-advanced.html#PRINTING-ADVANCED-NETWORK-RM Printers Installed on Remote Hosts] for more information on remote printing.\r
834 \r
835 There is another specialized way to limit job sizes from remote printers; see section [printing-advanced.html#PRINTING-ADVANCED-RESTRICTING-REMOTE Restricting Jobs from Remote Printers].\r
836 \r
837 #### Restricting Jobs from Remote Printers \r
838 \r
839 The  **LPD**  spooling system provides several ways to restrict print jobs submitted from remote hosts:\r
840 \r
841 Host restrictions:: You can control from which remote hosts a local  **LPD**  accepts requests with the files `/etc/hosts.equiv` and `/etc/hosts.lpd`.  **LPD**  checks to see if an incoming request is from a host listed in either one of these files. If not,  **LPD**  refuses the request.\r
842 The format of these files is simple: one host name per line. Note that the file `/etc/hosts.equiv` is also used by the [ruserok(3)](http://leaf.dragonflybsd.org/cgi/web-man?command#ruserok&section3) protocol, and affects programs like [rsh(1)](http://leaf.dragonflybsd.org/cgi/web-man?command=rsh&section=1) and [rcp(1)](http://leaf.dragonflybsd.org/cgi/web-man?command=rcp&section=1), so be careful.\r
843 For example, here is the `/etc/hosts.lpd` file on the host `rose`:\r
844     \r
845     orchid\r
846     violet\r
847     madrigal.fishbaum.de\r
848 \r
849 This means `rose` will accept requests from the hosts `orchid`, `violet`, and `madrigal.fishbaum.de`. If any other host tries to access `rose`'s  **LPD** , the job will be refused.Size restrictions:: You can control how much free space there needs to remain on the filesystem where a spooling directory resides. Make a file called `minfree` in the spooling directory for the local printer. Insert in that file a number representing how many disk blocks (512 bytes) of free space there has to be for a remote job to be accepted.\r
850 This lets you insure that remote users will not fill your filesystem. You can also use it to give a certain priority to local users: they will be able to queue jobs long after the free disk space has fallen below the amount specified in the `minfree` file.\r
851 For example, let us add a `minfree` file for the printer `bamboo`. We examine `/etc/printcap` to find the spooling directory for this printer; here is `bamboo`'s entry:\r
852     \r
853     bamboo|ps|PS|S|panasonic|Panasonic KX-P4455 PostScript v51.4:\\r
854             :sh:sd#/var/spool/lpd/bamboo:sc:rgartists:mx#5000:\\r
855             :lp=/dev/ttyd5:ms#-parenb cs8 clocal crtscts:rw:mx#5000:\\r
856             :if=/usr/local/libexec/psif:\\r
857             :df=/usr/local/libexec/psdf:\r
858 \r
859 The spooling directory is given in the `sd` capability. We will make three megabytes (which is 6144 disk blocks) the amount of free disk space that must exist on the filesystem for  **LPD**  to accept remote jobs:\r
860     \r
861     # echo 6144 > /var/spool/lpd/bamboo/minfree\r
862 User restrictions:: You can control which remote users can print to local printers by specifying the `rs` capability in `/etc/printcap`. When `rs` appears in the entry for a locally-attached printer,  **LPD**  will accept jobs from remote hosts ***if*** the user submitting the job also has an account of the same login name on the local host. Otherwise,  **LPD**  refuses the job.\r
863 This capability is particularly useful in an environment where there are (for example) different departments sharing a network, and some users transcend departmental boundaries. By giving them accounts on your systems, they can use your printers from their own departmental systems. If you would rather allow them to use ***only*** your printers and not your computer resources, you can give them ***token*** accounts, with no home directory and a useless shell like `/usr/bin/false`.\r
864 \r
865 ### 11.4.5 Accounting for Printer Usage \r
866 \r
867 So, you need to charge for printouts. And why not? Paper and ink cost money. And then there are maintenance costs--printers are loaded with moving parts and tend to break down. You have examined your printers, usage patterns, and maintenance fees and have come up with a per-page (or per-foot, per-meter, or per-whatever) cost. Now, how do you actually start accounting for printouts?\r
868 \r
869 Well, the bad news is the  **LPD**  spooling system does not provide much help in this department. Accounting is highly dependent on the kind of printer in use, the formats being printed, and ***your*** requirements in charging for printer usage.\r
870 \r
871 To implement accounting, you have to modify a printer's text filter (to charge for plain text jobs) and the conversion filters (to charge for other file formats), to count pages or query the printer for pages printed. You cannot get away with using the simple output filter, since it cannot do accounting. See section [printing-advanced.html#PRINTING-ADVANCED-FILTER-INTRO Filters].\r
872 \r
873 Generally, there are two ways to do accounting:\r
874 \r
876 * ***Periodic accounting*** is the more common way, possibly because it is easier. Whenever someone prints a job, the filter logs the user, host, and number of pages to an accounting file. Every month, semester, year, or whatever time period you prefer, you collect the accounting files for the various printers, tally up the pages printed by users, and charge for usage. Then you truncate all the logging files, starting with a clean slate for the next period.\r
878 * ***Timely accounting*** is less common, probably because it is more difficult. This method has the filters charge users for printouts as soon as they use the printers. Like disk quotas, the accounting is immediate. You can prevent users from printing when their account goes in the red, and might provide a way for users to check and adjust their ***print quotas.*** But this method requires some database code to track users and their quotas.\r
879 \r
880 The  **LPD**  spooling system supports both methods easily: since you have to provide the filters (well, most of the time), you also have to provide the accounting code. But there is a bright side: you have enormous flexibility in your accounting methods. For example, you choose whether to use periodic or timely accounting. You choose what information to log: user names, host names, job types, pages printed, square footage of paper used, how long the job took to print, and so forth. And you do so by modifying the filters to save this information.\r
881 \r
882 #### Quick and Dirty Printer Accounting \r
883 \r
884 DragonFly comes with two programs that can get you set up with simple periodic accounting right away. They are the text filter `lpf`, described in section [printing-advanced.html#PRINTING-ADVANCED-LPF lpf: a Text Filter], and [pac(8)](http://leaf.dragonflybsd.org/cgi/web-man?command#pac&section8), a program to gather and total entries from printer accounting files.\r
885 \r
886 As mentioned in the section on filters ([printing-advanced.html#PRINTING-ADVANCED-FILTERS Filters]),  **LPD**  starts the text and the conversion filters with the name of the accounting file to use on the filter command line. The filters can use this argument to know where to write an accounting file entry. The name of this file comes from the `af` capability in `/etc/printcap`, and if not specified as an absolute path, is relative to the spooling directory.\r
887 \r
888  **LPD**  starts `lpf` with page width and length arguments (from the `pw` and `pl` capabilities). `lpf` uses these arguments to determine how much paper will be used. After sending the file to the printer, it then writes an accounting entry in the accounting file. The entries look like this:\r
889 \r
890     \r
891     2.00 rose:andy\r
892     3.00 rose:kelly\r
893     3.00 orchid:mary\r
894     5.00 orchid:mary\r
895     2.00 orchid:zhang\r
896 \r
897 \r
898 You should use a separate accounting file for each printer, as `lpf` has no file locking logic built into it, and two `lpf`s might corrupt each other's entries if they were to write to the same file at the same time. An easy way to insure a separate accounting file for each printer is to use `af=acct` in `/etc/printcap`. Then, each accounting file will be in the spooling directory for a printer, in a file named `acct`.\r
899 \r
900 When you are ready to charge users for printouts, run the [pac(8)](http://leaf.dragonflybsd.org/cgi/web-man?command#pac&section8) program. Just change to the spooling directory for the printer you want to collect on and type `pac`. You will get a dollar-centric summary like the following:\r
901 \r
902     \r
903       Login               pages/feet   runs    price\r
904     orchid:kelly                5.00    1   $  0.10\r
905     orchid:mary                31.00    3   $  0.62\r
906     orchid:zhang                9.00    1   $  0.18\r
907     rose:andy                   2.00    1   $  0.04\r
908     rose:kelly                177.00  104   $  3.54\r
909     rose:mary                  87.00   32   $  1.74\r
910     rose:root                  26.00   12   $  0.52\r
911     \r
912     total                     337.00  154   $  6.74\r
913 \r
914 \r
915 These are the arguments [pac(8)](http://leaf.dragonflybsd.org/cgi/web-man?command#pac&section8) expects:\r
916 \r
917 `-P`***printer******:: Which `***printer***` to summarize. This option works only if there is an absolute path in the `af` capability in `/etc/printcap`.`-c`:: Sort the output by cost instead of alphabetically by user name.`-m`:: Ignore host name in the accounting files. With this option, user `smith` on host `alpha` is the same user `smith` on host `gamma`. Without, they are different users.`-p`***price******:: Compute charges with `***price***` dollars per page or per foot instead of the price from the `pc` capability in `/etc/printcap`, or two cents (the default). You can specify `***price***` as a floating point number.`-r`:: Reverse the sort order.`-s`:: Make an accounting summary file and truncate the accounting file.`***name***` `***...***`:: Print accounting information for the given user `***names***` only.\r
918 \r
919 In the default summary that [pac(8)](http://leaf.dragonflybsd.org/cgi/web-man?command#pac&section8) produces, you see the number of pages printed by each user from various hosts. If, at your site, host does not matter (because users can use any host), run `pac -m`, to produce the following summary:\r
920 \r
921     \r
922       Login               pages/feet   runs    price\r
923     andy                        2.00    1   $  0.04\r
924     kelly                     182.00  105   $  3.64\r
925     mary                      118.00   35   $  2.36\r
926     root                       26.00   12   $  0.52\r
927     zhang                       9.00    1   $  0.18\r
928     \r
929     total                     337.00  154   $  6.74\r
930 \r
931 \r
932 To compute the dollar amount due, [pac(8)](http://leaf.dragonflybsd.org/cgi/web-man?command#pac&section8) uses the `pc` capability in the `/etc/printcap` file (default of 200, or 2 cents per page). Specify, in hundredths of cents, the price per page or per foot you want to charge for printouts in this capability. You can override this value when you run [pac(8)](http://leaf.dragonflybsd.org/cgi/web-man?command=pac&section=8) with the `-p` option. The units for the `-p` option are in dollars, though, not hundredths of cents. For example,\r
933 \r
934     \r
935     # pac -p1.50\r
936 \r
937 \r
938  makes each page cost one dollar and fifty cents. You can really rake in the profits by using this option.\r
939 \r
940 Finally, running `pac -s` will save the summary information in a summary accounting file, which is named the same as the printer's accounting file, but with `_sum` appended to the name. It then truncates the accounting file. When you run [pac(8)](http://leaf.dragonflybsd.org/cgi/web-man?command#pac&section8) again, it rereads the summary file to get starting totals, then adds information from the regular accounting file.\r
941 \r
942 #### How Can You Count Pages Printed? \r
943 \r
944 In order to perform even remotely accurate accounting, you need to be able to determine how much paper a job uses. This is the essential problem of printer accounting.\r
945 \r
946 For plain text jobs, the problem is not that hard to solve: you count how many lines are in a job and compare it to how many lines per page your printer supports. Do not forget to take into account backspaces in the file which overprint lines, or long logical lines that wrap onto one or more additional physical lines.\r
947 \r
948 The text filter `lpf` (introduced in [printing-advanced.html#PRINTING-ADVANCED-LPF lpf: a Text Filter]) takes into account these things when it does accounting. If you are writing a text filter which needs to do accounting, you might want to examine `lpf`'s source code.\r
949 \r
950 How do you handle other file formats, though?\r
951 \r
952 Well, for DVI-to-LaserJet or DVI-to-PostScript conversion, you can have your filter parse the diagnostic output of `dvilj` or `dvips` and look to see how many pages were converted. You might be able to do similar things with other file formats and conversion programs.\r
953 \r
954 But these methods suffer from the fact that the printer may not actually print all those pages. For example, it could jam, run out of toner, or explode--and the user would still get charged.\r
955 \r
956 So, what can you do?\r
957 \r
958 There is only one ***sure*** way to do ***accurate*** accounting. Get a printer that can tell you how much paper it uses, and attach it via a serial line or a network connection. Nearly all PostScript printers support this notion. Other makes and models do as well (networked Imagen laser printers, for example). Modify the filters for these printers to get the page usage after they print each job and have them log accounting information based on that value ***only***. There is no line counting nor error-prone file examination required.\r
959 \r
960 Of course, you can always be generous and make all printouts free.\r
961 \r
962 \r
963 \r
964 CategoryHandbook\r
965 CategoryHandbook-printing\r