-CHANGES.txt - 03/08/2001
+CHANGES.txt - 03/14/2001
------------------------
CHANGES IN CUPS V1.1.7
attribute when altering a job.
- The pstops filter did not handle PostScript files with
lines longer than 8191 bytes.
+ - The scheduler no longer uses inet_addr() to convert IP
+ addresses in dot format (mmm.nnn.ooo.ppp) to the
+ 32-bit format, since it will not work for IPv6
+ addresses.
+ - New "Classification" directive to force labeling of
+ the current classification on each page.
+ - New "page-label" attribute to add per-page labels
+ ("For Official Use Only", "Draft", etc.)
- The scheduler now sets the HTTPS environment variable
for CGI programs when a client connects using
encryption.
#
-# "$Id: cupsd.conf,v 1.31 2001/03/02 22:33:58 andy Exp $"
+# "$Id: cupsd.conf,v 1.32 2001/03/14 13:45:30 mike Exp $"
#
# Sample configuration file for the Common UNIX Printing System (CUPS)
# scheduler.
#AccessLog /var/log/cups/access_log
+#
+# Classification: the classification level of the server. If set, this
+# classification is displayed on all pages, and raw printing is disabled.
+# The default is the empty string.
+
+#Classification classified
+#Classification confidential
+#Classification secret
+#Classification topsecret
+#Classification unclassified
+
#
# DataDir: the root directory for the CUPS data files.
# By default /usr/share/cups.
</Location>
#
-# End of "$Id: cupsd.conf,v 1.31 2001/03/02 22:33:58 andy Exp $".
+# End of "$Id: cupsd.conf,v 1.32 2001/03/14 13:45:30 mike Exp $".
#
<P>The page-bottom attribute specifies the bottom margin in points (72 points
equals 1 inch). The default value is the device physical margin.
+<H3>page-label (text(MAX))</H3>
+
+<P><I>(CUPS 1.1.7 and higher)</I>
+
+<P>The page-label attribute provides a text value to place in
+the header and footer on each page. If a classification level is
+set on the server, then this classification is printed before
+the page label.
+
<H3>page-left (integer(0:MAX))</H3>
<P>The page-left attribute specifies the left margin in points (72 points
<UL>
-
<TABLE CELLPADDING="0" CELLSPACING="0" BORDER="0">
<TR>
<TD VALIGN="TOP">
<LI><A HREF="#BrowseShortNames"><CODE>BrowseShortNames</CODE></A>
<LI><A HREF="#BrowseTimeout"><CODE>BrowseTimeout</CODE></A>
<LI><A HREF="#Browsing"><CODE>Browsing</CODE></A>
+ <LI><A HREF="#Classification"><CODE>Classification</CODE></A>
<LI><A HREF="#DataDir"><CODE>DataDir</CODE></A>
<LI><A HREF="#DefaultCharset"><CODE>DefaultCharset</CODE></A>
<LI><A HREF="#DefaultLanguage"><CODE>DefaultLanguage</CODE></A>
</TR>
</TABLE></CENTER>
+<!-- NEED 3in -->
+<H3><A NAME="Classification">Classification</A></H3>
+<HR>
+
+<H4>Examples</H4>
+
+<UL><PRE>
+Classification
+Classification classified
+Classification confidential
+Classification secret
+Classification topsecret
+Classification unclassified
+</PRE></UL>
+
+<H4>Description</H4>
+
+<P>The <CODE>Classification</CODE> directive sets the classification level
+on the server. When this option is set, at least one of the banner pages
+is forced to the classification level, and the classification is placed
+on each page of output. The default is no classification level.
+
<!-- NEED 3in -->
<H3><A NAME="DataDir">DataDir</A></H3>
<HR>
/*
- * "$Id: common.c,v 1.12 2001/01/22 15:03:37 mike Exp $"
+ * "$Id: common.c,v 1.13 2001/03/14 13:45:33 mike Exp $"
*
* Common filter routines for the Common UNIX Printing System (CUPS).
*
/*
- * End of "$Id: common.c,v 1.12 2001/01/22 15:03:37 mike Exp $".
+ * 'WriteClassificationProlog()' - Write the prolog with the classification
+ * and page label.
+ */
+
+void
+WriteLabelProlog(const char *label) /* I - Page label */
+{
+ const char *classification; /* CLASSIFICATION environment variable */
+
+
+ /*
+ * First get the current classification...
+ */
+
+ if ((classification = getenv("CLASSIFICATION")) == NULL)
+ classification = "";
+ if (strcmp(classification, "none") == 0)
+ classification = "";
+
+ /*
+ * Set the classification + page label string...
+ */
+
+ if (strcmp(classification, "confidential") == 0)
+ printf("/espPL(CONFIDENTIAL");
+ else if (strcmp(classification, "classified") == 0)
+ printf("/espPL(CLASSIFIED");
+ else if (strcmp(classification, "secret") == 0)
+ printf("/espPL(SECRET");
+ else if (strcmp(classification, "topsecret") == 0)
+ printf("/espPL(TOP SECRET");
+ else if (strcmp(classification, "unclassified") == 0)
+ printf("/espPL(UNCLASSIFIED");
+ else
+ printf("/espPL(");
+
+ if (classification[0] && label)
+ printf(" - %s)def\n", label);
+ else if (label)
+ printf("%s)def\n", label);
+ else
+ puts(")def");
+
+ /*
+ * Then get a 14 point Helvetica-Bold font...
+ */
+
+ puts("/espPF /Helvetica-Bold findfont 14 scalefont def");
+
+ /*
+ * Finally, the procedure to write the labels on the page...
+ */
+
+ puts("/espWL{");
+ puts(" espPF setfont");
+ printf(" espPL stringwidth pop dup 12 add exch -0.5 mul %.0f add\n",
+ PageWidth * 0.5f);
+ puts(" 1 setgray");
+ printf(" dup 6 sub %.0f 3 index 20 rectfill\n", PageBottom - 2.0);
+ printf(" dup 6 sub %.0f 3 index 20 rectfill\n", PageTop - 18.0);
+ puts(" 0 setgray");
+ printf(" dup 6 sub %.0f 3 index 20 rectstroke\n", PageBottom - 2.0);
+ printf(" dup 6 sub %.0f 3 index 20 rectstroke\n", PageTop - 18.0);
+ printf(" dup %.0f moveto espPL show\n", PageBottom + 2.0);
+ printf(" %.0f moveto espPL show\n", PageTop - 14.0);
+ puts("pop");
+ puts("}bind def");
+}
+
+
+/*
+ * End of "$Id: common.c,v 1.13 2001/03/14 13:45:33 mike Exp $".
*/
/*
- * "$Id: common.h,v 1.5 2001/01/22 15:03:37 mike Exp $"
+ * "$Id: common.h,v 1.6 2001/03/14 13:45:33 mike Exp $"
*
* Common filter definitions for the Common UNIX Printing System (CUPS).
*
extern ppd_file_t *SetCommonOptions(int num_options, cups_option_t *options,
int change_size);
+extern void WriteLabelProlog(const char *label);
+#define WriteLabels() puts("espWL");
/*
- * End of "$Id: common.h,v 1.5 2001/01/22 15:03:37 mike Exp $".
+ * End of "$Id: common.h,v 1.6 2001/03/14 13:45:33 mike Exp $".
*/
/*
- * "$Id: imagetops.c,v 1.35 2001/03/02 13:42:20 mike Exp $"
+ * "$Id: imagetops.c,v 1.36 2001/03/14 13:45:33 mike Exp $"
*
* Image file to PostScript filter for the Common UNIX Printing System (CUPS).
*
printf("{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
"ifelse %.3f mul } bind settransfer\n", g, b);
+ WriteLabelProlog(cupsGetOption("page-label", num_options, options));
+
if (Copies > 1 && !slowcollate)
{
if (ppd == NULL || ppd->language_level == 1)
}
puts("grestore");
+ WriteLabels();
puts("showpage");
}
/*
- * End of "$Id: imagetops.c,v 1.35 2001/03/02 13:42:20 mike Exp $".
+ * End of "$Id: imagetops.c,v 1.36 2001/03/14 13:45:33 mike Exp $".
*/
/*
- * "$Id: pstops.c,v 1.52 2001/03/09 18:23:36 mike Exp $"
+ * "$Id: pstops.c,v 1.53 2001/03/14 13:45:33 mike Exp $"
*
* PostScript filter for the Common UNIX Printing System (CUPS).
*
ppdEmit(ppd, stdout, PPD_ORDER_ANY);
ppdEmit(ppd, stdout, PPD_ORDER_PROLOG);
- if (NUp > 1)
- puts("userdict begin\n"
- "/ESPshowpage /showpage load def\n"
- "/showpage { } def\n"
- "end");
+ puts("userdict begin\n"
+ "/ESPshowpage /showpage load def\n"
+ "/showpage { } def\n"
+ "end");
if (g != 1.0 || b != 1.0)
printf("{ neg 1 add dup 0 lt { pop 1 } { %.3f exp neg 1 add } "
"ifelse %.3f mul } bind settransfer\n", g, b);
+ WriteLabelProlog(cupsGetOption("page-label", num_options, options));
+
if (Copies > 1 && (!Collate || !slowcollate))
{
if (ppd == NULL || ppd->language_level == 1)
switch (NUp)
{
+ case 1 :
+ WriteLabels();
+ puts("ESPshowpage");
+ break;
+
case 2 :
if ((number & 1) == 1)
+ {
+ WriteLabels();
puts("ESPshowpage");
+ }
break;
case 4 :
if ((number & 3) == 3)
+ {
+ WriteLabels();
puts("ESPshowpage");
+ }
break;
}
}
/*
- * End of "$Id: pstops.c,v 1.52 2001/03/09 18:23:36 mike Exp $".
+ * End of "$Id: pstops.c,v 1.53 2001/03/14 13:45:33 mike Exp $".
*/
/*
- * "$Id: conf.c,v 1.75 2001/03/12 19:26:49 mike Exp $"
+ * "$Id: conf.c,v 1.76 2001/03/14 13:45:34 mike Exp $"
*
* Configuration routines for the Common UNIX Printing System (CUPS).
*
{ "BrowseShortNames", &BrowseShortNames, VAR_BOOLEAN, 0 },
{ "BrowseTimeout", &BrowseTimeout, VAR_INTEGER, 0 },
{ "Browsing", &Browsing, VAR_BOOLEAN, 0 },
+ { "Classification", Classification, VAR_STRING, sizeof(Classification) },
{ "DataDir", DataDir, VAR_STRING, sizeof(DataDir) },
{ "DefaultCharset", DefaultCharset, VAR_STRING, sizeof(DefaultCharset) },
{ "DefaultLanguage", DefaultLanguage, VAR_STRING, sizeof(DefaultLanguage) },
strcpy(FontPath, CUPS_FONTPATH);
strcpy(RemoteRoot, "remroot");
+ Classification[0] = '\0';
+
#ifdef HAVE_LIBSSL
strcpy(ServerCertificate, "ssl/server.crt");
strcpy(ServerKey, "ssl/server.key");
/*
- * End of "$Id: conf.c,v 1.75 2001/03/12 19:26:49 mike Exp $".
+ * End of "$Id: conf.c,v 1.76 2001/03/14 13:45:34 mike Exp $".
*/
/*
- * "$Id: conf.h,v 1.35 2001/02/21 21:26:15 mike Exp $"
+ * "$Id: conf.h,v 1.36 2001/03/14 13:45:34 mike Exp $"
*
* Configuration file definitions for the Common UNIX Printing System (CUPS)
* scheduler.
/* Printcap file */
FontPath[1024] VALUE(CUPS_FONTPATH),
/* Font search path */
- RemoteRoot[32] VALUE("remroot");
+ RemoteRoot[32] VALUE("remroot"),
/* Remote root user */
+ Classification[IPP_MAX_NAME] VALUE("");
+ /* Classification of system */
VAR int User VALUE(1),
/* User ID for server */
Group VALUE(0),
/*
- * End of "$Id: conf.h,v 1.35 2001/02/21 21:26:15 mike Exp $".
+ * End of "$Id: conf.h,v 1.36 2001/03/14 13:45:34 mike Exp $".
*/
/*
- * "$Id: ipp.c,v 1.121 2001/03/02 17:35:04 mike Exp $"
+ * "$Id: ipp.c,v 1.122 2001/03/14 13:45:34 mike Exp $"
*
* IPP routines for the Common UNIX Printing System (CUPS) scheduler.
*
sizeof(pclass->job_sheets[1]) - 1);
else
strcpy(pclass->job_sheets[1], "none");
+
+ /*
+ * Enforce classification level if set...
+ */
+
+ if (Classification[0])
+ {
+ if (strcmp(pclass->job_sheets[0], Classification) != 0 &&
+ strcmp(pclass->job_sheets[1], Classification) != 0)
+ {
+ /*
+ * Force the leading banner to have the classification on it...
+ */
+
+ strcpy(pclass->job_sheets[0], Classification);
+ }
+ }
+
}
if ((attr = ippFindAttribute(con->request, "requesting-user-name-allowed",
IPP_TAG_ZERO)) != NULL)
sizeof(printer->job_sheets[1]) - 1);
else
strcpy(printer->job_sheets[1], "none");
+
+ /*
+ * Force classification if necessary...
+ */
+
+ if (Classification[0])
+ {
+ if (strcmp(pclass->job_sheets[0], Classification) != 0 &&
+ strcmp(pclass->job_sheets[1], Classification) != 0)
+ {
+ /*
+ * Force the leading banner to have the classification on it...
+ */
+
+ strcpy(pclass->job_sheets[0], Classification);
+ }
+ }
}
if ((attr = ippFindAttribute(con->request, "requesting-user-name-allowed",
IPP_TAG_ZERO)) != NULL)
job->state->values[0].integer = IPP_JOB_HELD;
- if (!(printer->type & CUPS_PRINTER_REMOTE))
+ if (!(printer->type & CUPS_PRINTER_REMOTE) || Classification[0])
{
/*
* Add job sheets options...
attr->values[1].string.text = strdup(printer->job_sheets[1]);
}
+ /*
+ * Enforce classification level if set...
+ */
+
+ if (Classification[0])
+ {
+ if (strcmp(attr->values[0].string.text, Classification) != 0 &&
+ (attr->num_values == 1 ||
+ strcmp(attr->values[1].string.text, Classification) != 0))
+ {
+ /*
+ * Force the leading banner to have the classification on it...
+ */
+
+ free(attr->values[0].string.text);
+ attr->values[0].string.text = strdup(Classification);
+ }
+ }
+
/*
* See if we need to add the starting sheet...
*/
SetJobHoldUntil(job->id, attr->values[0].string.text);
}
- if (!(printer->type & CUPS_PRINTER_REMOTE))
+ if (!(printer->type & CUPS_PRINTER_REMOTE) || Classification[0])
{
/*
* Add job sheets options...
attr->values[1].string.text = strdup(printer->job_sheets[1]);
}
+ /*
+ * Enforce classification level if set...
+ */
+
+ if (Classification[0])
+ {
+ if (strcmp(attr->values[0].string.text, Classification) != 0 &&
+ (attr->num_values == 1 ||
+ strcmp(attr->values[1].string.text, Classification) != 0))
+ {
+ /*
+ * Force the leading banner to have the classification on it...
+ */
+
+ free(attr->values[0].string.text);
+ attr->values[0].string.text = strdup(Classification);
+ }
+ }
+
/*
* Add the starting sheet...
*/
/*
- * End of "$Id: ipp.c,v 1.121 2001/03/02 17:35:04 mike Exp $".
+ * End of "$Id: ipp.c,v 1.122 2001/03/14 13:45:34 mike Exp $".
*/
/*
- * "$Id: job.c,v 1.118 2001/03/02 14:30:16 mike Exp $"
+ * "$Id: job.c,v 1.119 2001/03/14 13:45:34 mike Exp $"
*
* Job management routines for the Common UNIX Printing System (CUPS).
*
*envp[20], /* Environment variables */
language[255], /* LANG environment variable */
charset[255], /* CHARSET environment variable */
+ classification[1024], /* CLASSIFICATION environmeent variable */
content_type[255],/* CONTENT_TYPE environment variable */
device_uri[1024],/* DEVICE_URI environment variable */
ppd[1024], /* PPD environment variable */
continue;
if (strncmp(attr->name, "job-", 4) == 0 &&
+ strcmp(attr->name, "job-billing") != 0 &&
strcmp(attr->name, "job-sheets") != 0 &&
strcmp(attr->name, "job-hold-until") != 0 &&
strcmp(attr->name, "job-priority") != 0)
snprintf(tmpdir, sizeof(tmpdir), "TMPDIR=%s", TempDir);
snprintf(datadir, sizeof(datadir), "CUPS_DATADIR=%s", DataDir);
snprintf(fontpath, sizeof(fontpath), "CUPS_FONTPATH=%s", FontPath);
-
+ snprintf(classification, sizeof(classification), "CLASSIFICATION=%s",
+ Classification);
if (getenv("LD_LIBRARY_PATH") != NULL)
snprintf(ldpath, sizeof(ldpath), "LD_LIBRARY_PATH=%s", getenv("LD_LIBRARY_PATH"));
else
envp[13] = datadir;
envp[14] = fontpath;
envp[15] = ldpath;
- envp[16] = NULL;
+ envp[16] = classification;
+ envp[17] = NULL;
LogMessage(L_DEBUG, "StartJob: envp = \"%s\",\"%s\",\"%s\",\"%s\","
"\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\","
- "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"",
+ "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"",
envp[0], envp[1], envp[2], envp[3], envp[4],
envp[5], envp[6], envp[7], envp[8], envp[9],
envp[10], envp[11], envp[12], envp[13], envp[14],
- envp[15]);
+ envp[15], envp[16]);
current->current_file ++;
/*
- * End of "$Id: job.c,v 1.118 2001/03/02 14:30:16 mike Exp $".
+ * End of "$Id: job.c,v 1.119 2001/03/14 13:45:34 mike Exp $".
*/
/*
- * "$Id: printers.c,v 1.89 2001/02/21 21:26:16 mike Exp $"
+ * "$Id: printers.c,v 1.90 2001/03/14 13:45:35 mike Exp $"
*
* Printer routines for the Common UNIX Printing System (CUPS).
*
p->accepting = 0;
p->filetype = mimeAddType(MimeDatabase, "printer", name);
- strcpy(p->job_sheets[0], "none");
+ if (Classification[0])
+ strcpy(p->job_sheets[0], Classification);
+ else
+ strcpy(p->job_sheets[0], "none");
+
strcpy(p->job_sheets[1], "none");
/*
* Setup the job-sheets-supported and job-sheets-default attributes...
*/
- attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
- "job-sheets-supported", NumBanners + 1, NULL, NULL);
- attr->values[0].string.text = strdup("none");
- for (i = 0; i < NumBanners; i ++)
- attr->values[i + 1].string.text = strdup(Banners[i].name);
+ if (Classification[0])
+ attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "job-sheets-supported", 2, NULL, NULL);
+ else
+ attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+ "job-sheets-supported", NumBanners + 1, NULL, NULL);
+
+ if (attr == NULL)
+ LogMessage(L_EMERG, "SetPrinterAttrs: Unable to allocate memory for "
+ "job-sheets-supported attribute: %s!",
+ strerror(errno));
+ else
+ {
+ attr->values[0].string.text = strdup("none");
+
+ if (Classification[0])
+ attr->values[1].string.text = strdup(Classification);
+ else
+ {
+ for (i = 0; i < NumBanners; i ++)
+ attr->values[i + 1].string.text = strdup(Banners[i].name);
+ }
+ }
attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
"job-sheets-default", 2, NULL, NULL);
- attr->values[0].string.text = strdup(p->job_sheets[0]);
- attr->values[1].string.text = strdup(p->job_sheets[1]);
+
+ if (attr != NULL)
+ {
+ attr->values[0].string.text = strdup(p->job_sheets[0]);
+ attr->values[1].string.text = strdup(p->job_sheets[1]);
+ }
}
if (p->type & CUPS_PRINTER_REMOTE)
attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
"member-uris", p->num_printers, NULL, NULL);
-
p->type |= CUPS_PRINTER_OPTIONS;
for (i = 0; i < p->num_printers; i ++)
{
- attr->values[i].string.text = strdup(p->printers[i]->uri);
+ if (attr != NULL)
+ attr->values[i].string.text = strdup(p->printers[i]->uri);
p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
}
attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
"member-names", p->num_printers, NULL, NULL);
- for (i = 0; i < p->num_printers; i ++)
- attr->values[i].string.text = strdup(p->printers[i]->name);
+ if (attr != NULL)
+ {
+ for (i = 0; i < p->num_printers; i ++)
+ attr->values[i].string.text = strdup(p->printers[i]->name);
+ }
}
}
else
attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
"media-supported", num_media, NULL, NULL);
- val = attr->values;
-
- if (input_slot != NULL)
- for (i = 0; i < input_slot->num_choices; i ++, val ++)
- val->string.text = strdup(input_slot->choices[i].choice);
-
- if (media_type != NULL)
- for (i = 0; i < media_type->num_choices; i ++, val ++)
- val->string.text = strdup(media_type->choices[i].choice);
-
- if (page_size != NULL)
+ if (attr != NULL)
{
- for (i = 0; i < page_size->num_choices; i ++, val ++)
- val->string.text = strdup(page_size->choices[i].choice);
-
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
- NULL, page_size->defchoice);
+ val = attr->values;
+
+ if (input_slot != NULL)
+ for (i = 0; i < input_slot->num_choices; i ++, val ++)
+ val->string.text = strdup(input_slot->choices[i].choice);
+
+ if (media_type != NULL)
+ for (i = 0; i < media_type->num_choices; i ++, val ++)
+ val->string.text = strdup(media_type->choices[i].choice);
+
+ if (page_size != NULL)
+ {
+ for (i = 0; i < page_size->num_choices; i ++, val ++)
+ val->string.text = strdup(page_size->choices[i].choice);
+
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
+ NULL, page_size->defchoice);
+ }
+ else if (input_slot != NULL)
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
+ NULL, input_slot->defchoice);
+ else if (media_type != NULL)
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
+ NULL, media_type->defchoice);
+ else
+ ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
+ NULL, "none");
}
- else if (input_slot != NULL)
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
- NULL, input_slot->defchoice);
- else if (media_type != NULL)
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
- NULL, media_type->defchoice);
- else
- ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default",
- NULL, "none");
/*
* Output bin...
"output-bin-supported", output_bin->num_choices,
NULL, NULL);
- for (i = 0, val = attr->values;
- i < output_bin->num_choices;
- i ++, val ++)
- val->string.text = strdup(output_bin->choices[i].choice);
- }
+ if (attr != NULL)
+ {
+ for (i = 0, val = attr->values;
+ i < output_bin->num_choices;
+ i ++, val ++)
+ val->string.text = strdup(output_bin->choices[i].choice);
+ }
+ }
/*
* Duplexing, etc...
/*
- * End of "$Id: printers.c,v 1.89 2001/02/21 21:26:16 mike Exp $".
+ * End of "$Id: printers.c,v 1.90 2001/03/14 13:45:35 mike Exp $".
*/