]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/printers.c
Remove old logging of IPP conformance issues.
[thirdparty/cups.git] / scheduler / printers.c
index 0119342326fd680d123303d5a1b1993c5b7d8569..f4eac5c72ae68548c9e0a7b58bd843d3c04bba23 100644 (file)
@@ -1,59 +1,16 @@
 /*
- * "$Id: printers.c 7968 2008-09-19 23:03:01Z mike $"
+ * "$Id$"
  *
- *   Printer routines for the CUPS scheduler.
+ * Printer routines for the CUPS scheduler.
  *
- *   Copyright 2007-2012 by Apple Inc.
- *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ * Copyright 2007-2014 by Apple Inc.
+ * Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
- *   These coded instructions, statements, and computer programs are the
- *   property of Apple Inc. and are protected by Federal copyright
- *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
- *   which should have been included with this file.  If this file is
- *   file is missing or damaged, see the license at "http://www.cups.org/".
- *
- * Contents:
- *
- *   cupsdAddPrinter()          - Add a printer to the system.
- *   cupsdCreateCommonData()    - Create the common printer data.
- *   cupsdDeleteAllPrinters()   - Delete all printers from the system.
- *   cupsdDeletePrinter()       - Delete a printer from the system.
- *   cupsdFindDest()            - Find a destination in the list.
- *   cupsdFindPrinter()         - Find a printer in the list.
- *   cupsdLoadAllPrinters()     - Load printers from the printers.conf file.
- *   cupsdRenamePrinter()       - Rename a printer.
- *   cupsdSaveAllPrinters()     - Save all printer definitions to the
- *                                printers.conf file.
- *   cupsdSetAuthInfoRequired() - Set the required authentication info.
- *   cupsdSetDeviceURI()        - Set the device URI for a printer.
- *   cupsdSetPrinterAttr()      - Set a printer attribute.
- *   cupsdSetPrinterAttrs()     - Set printer attributes based upon the PPD
- *                                file.
- *   cupsdSetPrinterReasons()   - Set/update the reasons strings.
- *   cupsdSetPrinterState()     - Update the current state of a printer.
- *   cupsdStopPrinter()         - Stop a printer from printing any jobs...
- *   cupsdUpdatePrinterPPD()    - Update keywords in a printer's PPD file.
- *   cupsdUpdatePrinters()      - Update printers after a partial reload.
- *   cupsdValidateDest()        - Validate a printer/class destination.
- *   cupsdWritePrintcap()       - Write a pseudo-printcap file for older
- *                                applications that need it...
- *   add_printer_defaults()     - Add name-default attributes to the printer
- *                                attributes.
- *   add_printer_filter()       - Add a MIME filter for a printer.
- *   add_printer_formats()      - Add document-format-supported values for a
- *                                printer.
- *   compare_printers()         - Compare two printers.
- *   delete_printer_filters()   - Delete all MIME filters for a printer.
- *   dirty_printer()            - Mark config and state files dirty for the
- *                                specified printer.
- *   load_ppd()                 - Load a cached PPD file, updating the cache as
- *                                needed.
- *   new_media_col()            - Create a media-col collection value.
- *   write_irix_config()        - Update the config files used by the IRIX
- *                                desktop tools.
- *   write_irix_state()         - Update the status files used by IRIX printing
- *                                desktop tools.
- *   write_xml_string()         - Write a string with XML escaping.
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ * which should have been included with this file.  If this file is
+ * file is missing or damaged, see the license at "http://www.cups.org/".
  */
 
 /*
@@ -93,13 +50,8 @@ static int   compare_printers(void *first, void *second, void *data);
 static void    delete_printer_filters(cupsd_printer_t *p);
 static void    dirty_printer(cupsd_printer_t *p);
 static void    load_ppd(cupsd_printer_t *p);
-static void    log_ipp_conformance(cupsd_printer_t *p, const char *reason);
 static ipp_t   *new_media_col(_pwg_size_t *size, const char *source,
                               const char *type);
-#ifdef __sgi
-static void    write_irix_config(cupsd_printer_t *p);
-static void    write_irix_state(cupsd_printer_t *p);
-#endif /* __sgi */
 static void    write_xml_string(cups_file_t *fp, const char *s);
 
 
@@ -139,8 +91,8 @@ cupsdAddPrinter(const char *name)    /* I - Name of printer */
   httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
                   ServerName, RemotePort, "/printers/%s", name);
   cupsdSetString(&p->uri, uri);
-  cupsdSetString(&p->uuid, _httpAssembleUUID(ServerName, RemotePort, name, 0,
-                                             uuid, sizeof(uuid)));
+  cupsdSetString(&p->uuid, httpAssembleUUID(ServerName, RemotePort, name, 0,
+                                            uuid, sizeof(uuid)));
   cupsdSetDeviceURI(p, "file:///dev/null");
 
   p->state      = IPP_PRINTER_STOPPED;
@@ -348,9 +300,9 @@ cupsdCreateCommonData(void)
                  "multiple-document-handling",
                  "number-up",
                  "output-bin",
-                 "output-mode",
                  "orientation-requested",
                  "page-ranges",
+                 "print-color-mode",
                  "print-quality",
                  "printer-resolution",
                  "sides"
@@ -367,9 +319,9 @@ cupsdCreateCommonData(void)
                  "multiple-document-handling",
                  "number-up",
                  "output-bin",
-                 "output-mode",
                  "orientation-requested",
                  "page-ranges",
+                 "print-color-mode",
                  "print-quality",
                  "printer-resolution",
                  "sides"
@@ -478,6 +430,10 @@ cupsdCreateCommonData(void)
   ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
                 "ippget-event-life", 15);
 
+  /* job-cancel-after-supported */
+  ippAddRange(CommonData, IPP_TAG_PRINTER, "job-cancel-after-supported",
+              0, INT_MAX);
+
   /* job-creation-attributes-supported */
   ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
                 "job-creation-attributes-supported",
@@ -720,9 +676,6 @@ cupsdDeletePrinter(
 {
   int  i,                              /* Looping var */
        changed = 0;                    /* Class changed? */
-#ifdef __sgi
-  char filename[1024];                 /* Interface script filename */
-#endif /* __sgi */
 
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDeletePrinter(p=%p(%s), update=%d)",
@@ -755,31 +708,6 @@ cupsdDeletePrinter(
                   "cupsdDeletePrinter: Removing %s from Printers", p->name);
   cupsArrayRemove(Printers, p);
 
- /*
-  * Remove the dummy interface/icon/option files under IRIX...
-  */
-
-#ifdef __sgi
-  snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
-  unlink(filename);
-
-  snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui",
-           p->name);
-  unlink(filename);
-
-  snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
-  unlink(filename);
-
-  snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
-  unlink(filename);
-
-  snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
-  unlink(filename);
-
-  snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
-  unlink(filename);
-#endif /* __sgi */
-
  /*
   * If p is the default printer, assign a different one...
   */
@@ -1160,7 +1088,7 @@ cupsdLoadAllPrinters(void)
     else if (!_cups_strcasecmp(line, "Type"))
     {
       if (value)
-        p->type = atoi(value);
+        p->type = (cups_ptype_t)atoi(value);
       else
        cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Syntax error on line %d of printers.conf.", linenum);
@@ -1562,8 +1490,7 @@ cupsdSaveAllPrinters(void)
         if (i)
          *ptr++ = ',';
 
-        strlcpy(ptr, marker->values[i].string.text,
-               value + sizeof(value) - ptr);
+        strlcpy(ptr, marker->values[i].string.text, (size_t)(value + sizeof(value) - ptr));
         ptr += strlen(ptr);
       }
 
@@ -1622,8 +1549,7 @@ cupsdSaveAllPrinters(void)
         if (i)
          *ptr++ = ',';
 
-        strlcpy(ptr, marker->values[i].string.text,
-               value + sizeof(value) - ptr);
+        strlcpy(ptr, marker->values[i].string.text, (size_t)(value + sizeof(value) - ptr));
         ptr += strlen(ptr);
       }
 
@@ -1643,8 +1569,7 @@ cupsdSaveAllPrinters(void)
         if (i)
          *ptr++ = ',';
 
-        strlcpy(ptr, marker->values[i].string.text,
-               value + sizeof(value) - ptr);
+        strlcpy(ptr, marker->values[i].string.text, (size_t)(value + sizeof(value) - ptr));
         ptr += strlen(ptr);
       }
 
@@ -1657,14 +1582,6 @@ cupsdSaveAllPrinters(void)
                      (long)printer->marker_time);
 
     cupsFilePuts(fp, "</Printer>\n");
-
-#ifdef __sgi
-    /*
-     * Make IRIX desktop & printer status happy
-     */
-
-    write_irix_state(printer);
-#endif /* __sgi */
   }
 
   cupsdCloseCreatedConfFile(fp, filename);
@@ -1767,7 +1684,7 @@ cupsdSetAuthInfoRequired(
         strcmp(p->auth_info_required[0], "none"))
       p->type |= CUPS_PRINTER_AUTHENTICATED;
     else
-      p->type &= ~CUPS_PRINTER_AUTHENTICATED;
+      p->type &= (cups_ptype_t)~CUPS_PRINTER_AUTHENTICATED;
 
     return (1);
   }
@@ -1910,12 +1827,13 @@ void
 cupsdSetPrinterAttr(
     cupsd_printer_t *p,                        /* I - Printer */
     const char      *name,             /* I - Attribute name */
-    char            *value)            /* I - Attribute value string */
+    const char      *value)            /* I - Attribute value string */
 {
   ipp_attribute_t      *attr;          /* Attribute */
   int                  i,              /* Looping var */
                        count;          /* Number of values */
-  char                 *ptr,           /* Pointer into value */
+  char                 *temp,          /* Temporary copy of value string */
+                       *ptr,           /* Pointer into value */
                        *start,         /* Start of value */
                        quote;          /* Quote character */
   ipp_tag_t            value_tag;      /* Value tag for this attribute */
@@ -1931,11 +1849,22 @@ cupsdSetPrinterAttr(
     return;
   }
 
+ /*
+  * Copy the value string so we can do what we want with it...
+  */
+
+  if ((temp = strdup(value)) == NULL)
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR,
+                    "Unable to duplicate value for \"%s\" attribute.", name);
+    return;
+  }
+
  /*
   * Count the number of values...
   */
 
-  for (count = 1, quote = '\0', ptr = value;
+  for (count = 1, quote = '\0', ptr = temp;
        *ptr;
        ptr ++)
   {
@@ -1977,21 +1906,22 @@ cupsdSetPrinterAttr(
 
     if (!attr)
     {
+      free(temp);
       cupsdLogMessage(CUPSD_LOG_ERROR,
                       "Unable to allocate memory for printer attribute "
                      "(%d values)", count);
       return;
     }
 
-    for (i = 0; i < count; i ++)
+    for (i = 0, start = temp; i < count; i ++)
     {
-      if ((ptr = strchr(value, ',')) != NULL)
+      if ((ptr = strchr(start, ',')) != NULL)
         *ptr++ = '\0';
 
-      attr->values[i].integer = strtol(value, NULL, 10);
+      attr->values[i].integer = strtol(start, NULL, 10);
 
       if (ptr)
-        value = ptr;
+        start = ptr;
     }
   }
   else
@@ -2027,13 +1957,14 @@ cupsdSetPrinterAttr(
 
     if (!attr)
     {
+      free(temp);
       cupsdLogMessage(CUPSD_LOG_ERROR,
                       "Unable to allocate memory for printer attribute "
                      "(%d values)", count);
       return;
     }
 
-    for (i = 0, quote = '\0', ptr = value; i < count; i ++)
+    for (i = 0, quote = '\0', ptr = temp; i < count; i ++)
     {
       for (start = ptr; *ptr; ptr ++)
       {
@@ -2062,6 +1993,8 @@ cupsdSetPrinterAttr(
       attr->values[i].string.text = _cupsStrAlloc(start);
     }
   }
+
+  free(temp);
 }
 
 
@@ -2074,23 +2007,12 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
 {
   int          i;                      /* Looping var */
   char         resource[HTTP_MAX_URI]; /* Resource portion of URI */
-  int          num_air;                /* Number of auth-info-required values */
-  const char   * const *air;           /* auth-info-required values */
   cupsd_location_t *auth;              /* Pointer to authentication element */
   const char   *auth_supported;        /* Authentication supported */
   ipp_t                *oldattrs;              /* Old printer attributes */
   ipp_attribute_t *attr;               /* Attribute data */
   char         *name,                  /* Current user/group name */
                *filter;                /* Current filter */
-  static const char * const air_none[] =
-               {                       /* No authentication */
-                 "none"
-               };
-  static const char * const air_userpass[] =
-               {                       /* Basic/Digest authentication */
-                 "username",
-                 "password"
-               };
 
 
   DEBUG_printf(("cupsdSetPrinterAttrs: entering name = %s, type = %x\n", p->name,
@@ -2114,19 +2036,6 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
   */
 
   auth_supported = "requesting-user-name";
-  num_air        = 1;
-  air            = air_none;
-
-  if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none"))
-  {
-    num_air = p->num_auth_info_required;
-    air     = p->auth_info_required;
-  }
-  else if (p->type & CUPS_PRINTER_AUTHENTICATED)
-  {
-    num_air = 2;
-    air     = air_userpass;
-  }
 
   if (p->type & CUPS_PRINTER_CLASS)
     snprintf(resource, sizeof(resource), "/classes/%s", p->name);
@@ -2157,10 +2066,10 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
     if (auth_type != CUPSD_AUTH_NONE)
       p->type |= CUPS_PRINTER_AUTHENTICATED;
     else
-      p->type &= ~CUPS_PRINTER_AUTHENTICATED;
+      p->type &= (cups_ptype_t)~CUPS_PRINTER_AUTHENTICATED;
   }
   else
-    p->type &= ~CUPS_PRINTER_AUTHENTICATED;
+    p->type &= (cups_ptype_t)~CUPS_PRINTER_AUTHENTICATED;
 
  /*
   * Create the required IPP attributes for a printer...
@@ -2196,7 +2105,7 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
     for (i = 0, name = (char *)cupsArrayFirst(p->users);
          name;
         i ++, name = (char *)cupsArrayNext(p->users))
-      attr->values[i].string.text = _cupsStrRetain(name);
+      attr->values[i].string.text = _cupsStrAlloc(name);
   }
 
   ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
@@ -2205,8 +2114,10 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
                 "job-k-limit", p->k_limit);
   ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
                 "job-page-limit", p->page_limit);
-  ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-               "auth-info-required", num_air, NULL, air);
+  if (p->num_auth_info_required > 0 && strcmp(p->auth_info_required[0], "none"))
+    ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                 "auth-info-required", p->num_auth_info_required, NULL,
+                 p->auth_info_required);
 
   if (cupsArrayCount(Banners) > 0)
   {
@@ -2237,7 +2148,7 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
   if (p->type & CUPS_PRINTER_CLASS)
   {
     p->raw = 1;
-    p->type &= ~CUPS_PRINTER_OPTIONS;
+    p->type &= (cups_ptype_t)~CUPS_PRINTER_OPTIONS;
 
    /*
     * Add class-specific attributes...
@@ -2261,9 +2172,9 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
       for (i = 0; i < p->num_printers; i ++)
       {
        if (attr != NULL)
-         attr->values[i].string.text = _cupsStrRetain(p->printers[i]->name);
+         attr->values[i].string.text = _cupsStrAlloc(p->printers[i]->name);
 
-       p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
+       p->type &= (cups_ptype_t)~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
       }
     }
   }
@@ -2361,7 +2272,7 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
       {
        for (i = 0; i < oldattr->num_values; i ++)
          attr->values[i].string.text =
-             _cupsStrRetain(oldattr->values[i].string.text);
+             _cupsStrAlloc(oldattr->values[i].string.text);
       }
     }
 
@@ -2415,7 +2326,7 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
       {
        for (i = 0; i < oldattr->num_values; i ++)
          attr->values[i].string.text =
-             _cupsStrRetain(oldattr->values[i].string.text);
+             _cupsStrAlloc(oldattr->values[i].string.text);
       }
     }
 
@@ -2428,7 +2339,7 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
       {
        for (i = 0; i < oldattr->num_values; i ++)
          attr->values[i].string.text =
-             _cupsStrRetain(oldattr->values[i].string.text);
+             _cupsStrAlloc(oldattr->values[i].string.text);
       }
     }
 
@@ -2457,15 +2368,6 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
 
   add_printer_defaults(p);
 
-#ifdef __sgi
- /*
-  * Write the IRIX printer config and status files...
-  */
-
-  write_irix_config(p);
-  write_irix_state(p);
-#endif /* __sgi */
-
  /*
   * Let the browse protocols reflect the change
   */
@@ -2561,14 +2463,17 @@ cupsdSetPrinterReasons(
          _cupsStrFree(p->reasons[i]);
 
          if (i < p->num_reasons)
-           memmove(p->reasons + i, p->reasons + i + 1,
-                   (p->num_reasons - i) * sizeof(char *));
+           memmove(p->reasons + i, p->reasons + i + 1, (size_t)(p->num_reasons - i) * sizeof(char *));
 
           if (!strcmp(reason, "paused") && p->state == IPP_PRINTER_STOPPED)
            cupsdSetPrinterState(p, IPP_PRINTER_IDLE, 1);
 
+          if (!strcmp(reason, "cups-waiting-for-job-completed") && p->job)
+            p->job->completed = 0;
+
           if (strcmp(reason, "connecting-to-device"))
            dirty_printer(p);
+
          break;
        }
     }
@@ -2584,10 +2489,6 @@ cupsdSetPrinterReasons(
 
       if (i >= p->num_reasons)
       {
-        if (!strncmp(reason, "cups-ipp-missing-", 17) ||
-           !strncmp(reason, "cups-ipp-wrong-", 15))
-         log_ipp_conformance(p, reason);
-
         if (i >= (int)(sizeof(p->reasons) / sizeof(p->reasons[0])))
        {
          cupsdLogMessage(CUPSD_LOG_ALERT,
@@ -2603,6 +2504,9 @@ cupsdSetPrinterReasons(
        if (!strcmp(reason, "paused") && p->state != IPP_PRINTER_STOPPED)
          cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, 1);
 
+       if (!strcmp(reason, "cups-waiting-for-job-completed") && p->job)
+         p->job->completed = 1;
+
        if (strcmp(reason, "connecting-to-device"))
          dirty_printer(p);
       }
@@ -2653,10 +2557,6 @@ cupsdSetPrinterState(
     */
 
     p->state_time = time(NULL);
-
-#ifdef __sgi
-    write_irix_state(p);
-#endif /* __sgi */
   }
 
  /*
@@ -3045,16 +2945,6 @@ cupsdWritePrintcap(void)
   cupsd_printer_t      *p;             /* Current printer */
 
 
-#ifdef __sgi
- /*
-  * Update the IRIX printer state for the default printer; if
-  * no printers remain, then the default printer file will be
-  * removed...
-  */
-
-  write_irix_state(DefaultPrinter);
-#endif /* __sgi */
-
  /*
   * See if we have a printcap file; if not, don't bother writing it.
   */
@@ -3248,6 +3138,10 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */
     cupsArrayAdd(CommonDefaults, _cupsStrAlloc("copies-default"));
     cupsArrayAdd(CommonDefaults, _cupsStrAlloc("document-format-default"));
     cupsArrayAdd(CommonDefaults, _cupsStrAlloc("finishings-default"));
+    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-account-id-default"));
+    cupsArrayAdd(CommonDefaults,
+                 _cupsStrAlloc("job-accounting-user-id-default"));
+    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-cancel-after-default"));
     cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-hold-until-default"));
     cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-priority-default"));
     cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-sheets-default"));
@@ -3296,6 +3190,10 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */
     ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE,
                 "document-format-default", NULL, "application/octet-stream");
 
+  if (!cupsGetOption("job-cancel-after", p->num_options, p->options))
+    ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                 "job-cancel-after-default", MaxJobTime);
+
   if (!cupsGetOption("job-hold-until", p->num_options, p->options))
     ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
                  "job-hold-until-default", NULL, "no-hold");
@@ -3399,7 +3297,7 @@ add_printer_filter(
   {
     char       *ptr;                   /* Pointer into maxsize(nnnn) program */
 
-    maxsize = strtoll(program + 8, &ptr, 10);
+    maxsize = (size_t)strtoll(program + 8, &ptr, 10);
 
     if (*ptr != ')')
     {
@@ -3753,7 +3651,8 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
                qualities[3];           /* print-quality values */
   int          num_margins,            /* Number of media-*-margin-supported values */
                margins[16];            /* media-*-margin-supported values */
-  const char   *filter;                /* Current filter */
+  const char   *filter,                /* Current filter */
+               *mandatory;             /* Current mandatory attribute */
   static const char * const sides[3] = /* sides-supported values */
                {
                  "one-sided",
@@ -3809,7 +3708,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
 
   cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", ppd_name);
 
-  p->type &= ~CUPS_PRINTER_OPTIONS;
+  p->type &= (cups_ptype_t)~CUPS_PRINTER_OPTIONS;
   p->type |= CUPS_PRINTER_BW;
 
   finishings[0]  = IPP_FINISHINGS_NONE;
@@ -3825,6 +3724,10 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
 
     p->pc = _ppdCacheCreateWithPPD(ppd);
 
+    if (!p->pc)
+      cupsdLogMessage(CUPSD_LOG_WARN, "Unable to create cache of \"%s\": %s",
+                      ppd_name, cupsLastErrorString());
+
     ppdMarkDefaults(ppd);
 
     if (ppd->color_device)
@@ -3837,8 +3740,28 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
       if (ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true"))
        p->type |= CUPS_PRINTER_FAX;
 
-    ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, "color-supported",
-                 ppd->color_device);
+    ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, "color-supported", (char)ppd->color_device);
+
+    if (p->pc && p->pc->charge_info_uri)
+      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
+                   "printer-charge-info-uri", NULL, p->pc->charge_info_uri);
+
+    if (p->pc && p->pc->account_id)
+      ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, "job-account-id-supported",
+                    1);
+
+    if (p->pc && p->pc->accounting_user_id)
+      ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER,
+                    "job-accounting-user-id-supported", 1);
+
+    if (p->pc && p->pc->password)
+    {
+      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                   "job-password-encryption-supported", NULL, "none");
+      ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                    "job-password-supported", (int)strlen(p->pc->password));
+    }
+
     if (ppd->throughput)
     {
       ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
@@ -3995,13 +3918,48 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
         for (i = p->pc->num_sizes, pwgsize = p->pc->sizes;
             i > 0;
             i --, pwgsize ++, val ++)
-         val->string.text = _cupsStrRetain(pwgsize->map.pwg);
+         val->string.text = _cupsStrAlloc(pwgsize->map.pwg);
 
         if (p->pc->custom_min_keyword)
        {
-         val->string.text = _cupsStrRetain(p->pc->custom_min_keyword);
+         val->string.text = _cupsStrAlloc(p->pc->custom_min_keyword);
          val ++;
-         val->string.text = _cupsStrRetain(p->pc->custom_max_keyword);
+         val->string.text = _cupsStrAlloc(p->pc->custom_max_keyword);
+        }
+      }
+
+     /*
+      * media-size-supported
+      */
+
+      num_media = p->pc->num_sizes;
+      if (p->pc->custom_min_keyword)
+       num_media ++;
+
+      if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER,
+                                   "media-size-supported", num_media,
+                                   NULL)) != NULL)
+      {
+       val = attr->values;
+
+        for (i = p->pc->num_sizes, pwgsize = p->pc->sizes;
+            i > 0;
+            i --, pwgsize ++, val ++)
+       {
+         val->collection = ippNew();
+         ippAddInteger(val->collection, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                       "x-dimension", pwgsize->width);
+         ippAddInteger(val->collection, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                       "y-dimension", pwgsize->length);
+        }
+
+        if (p->pc->custom_min_keyword)
+       {
+         val->collection = ippNew();
+         ippAddRange(val->collection, IPP_TAG_PRINTER, "x-dimension",
+                     p->pc->custom_min_width, p->pc->custom_max_width);
+         ippAddRange(val->collection, IPP_TAG_PRINTER, "y-dimension",
+                     p->pc->custom_min_length, p->pc->custom_max_length);
         }
       }
 
@@ -4018,7 +3976,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
                 val = attr->values;
             i > 0;
             i --, pwgsource ++, val ++)
-         val->string.text = _cupsStrRetain(pwgsource->pwg);
+         val->string.text = _cupsStrAlloc(pwgsource->pwg);
       }
 
      /*
@@ -4034,7 +3992,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
                 val = attr->values;
             i > 0;
             i --, pwgtype ++, val ++)
-         val->string.text = _cupsStrRetain(pwgtype->pwg);
+         val->string.text = _cupsStrAlloc(pwgtype->pwg);
       }
 
      /*
@@ -4279,40 +4237,50 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
     }
 
    /*
-    * output-mode and print-color-mode...
+    * print-color-mode...
     */
 
     if (ppd->color_device)
     {
-      static const char * const output_modes[] =
+      static const char * const color_modes[] =
       {
         "monochrome",
        "color"
       };
 
       ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                    "output-mode-supported", 2, NULL, output_modes);
-      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                   "output-mode-default", NULL, "color");
-
-      ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                    "print-color-mode-supported", 2, NULL, output_modes);
+                    "print-color-mode-supported", 2, NULL, color_modes);
       ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
                    "print-color-mode-default", NULL, "color");
     }
     else
     {
-      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                   "output-mode-supported", NULL, "monochrome");
-      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                   "output-mode-default", NULL, "monochrome");
-
       ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
                    "print-color-mode-supported", NULL, "monochrome");
       ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
                    "print-color-mode-default", NULL, "monochrome");
     }
 
+   /*
+    * Mandatory job attributes, if any...
+    */
+
+    if (p->pc && cupsArrayCount(p->pc->mandatory) > 0)
+    {
+      int      count = cupsArrayCount(p->pc->mandatory);
+                                       /* Number of mandatory attributes */
+
+      attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                           "printer-mandatory-job-attributes", count, NULL,
+                           NULL);
+
+      for (val = attr->values,
+               mandatory = (char *)cupsArrayFirst(p->pc->mandatory);
+           mandatory;
+           val ++, mandatory = (char *)cupsArrayNext(p->pc->mandatory))
+        val->string.text = _cupsStrAlloc(mandatory);
+    }
+
    /*
     * Printer resolutions...
     */
@@ -4641,22 +4609,16 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
       CGContextRef     context;        /* The CG context used for resizing */
 
       snprintf(outPath, sizeof(outPath), "%s/%s.png", CacheDir, p->name);
-      outUrl      = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
-                                                            (UInt8 *)outPath,
-                                                           strlen(outPath),
-                                                           FALSE);
-      icnsFileUrl = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
-                                                           (UInt8 *)ppd_attr->value,
-                                                           strlen(ppd_attr->value),
-                                                           FALSE);
+      outUrl      = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8 *)outPath, (CFIndex)strlen(outPath), FALSE);
+      icnsFileUrl = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8 *)ppd_attr->value, (CFIndex)strlen(ppd_attr->value), FALSE);
       if (outUrl && icnsFileUrl)
       {
         sourceRef = CGImageSourceCreateWithURL(icnsFileUrl, NULL);
         if (sourceRef)
         {
-          for (i = 0; i < CGImageSourceGetCount(sourceRef); i ++)
+          for (i = 0; i < (int)CGImageSourceGetCount(sourceRef); i ++)
           {
-            imageRef = CGImageSourceCreateImageAtIndex(sourceRef, i, NULL);
+            imageRef = CGImageSourceCreateImageAtIndex(sourceRef, (size_t)i, NULL);
            if (!imageRef)
              continue;
 
@@ -4794,12 +4756,13 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
                   "printer-make-and-model", NULL,
                   "Local System V Printer");
     }
-    else if (!strncmp(p->device_uri, "ipp://", 6) &&
-            (strstr(p->device_uri, "/printers/") != NULL ||
-             strstr(p->device_uri, "/classes/") != NULL ||
-             (strstr(p->device_uri, "._ipp.") != NULL &&
-              !strcmp(p->device_uri + strlen(p->device_uri) - 5,
-                      "/cups"))))
+    else if (((!strncmp(p->device_uri, "ipp://", 6) ||
+               !strncmp(p->device_uri, "ipps://", 7)) &&
+             (strstr(p->device_uri, "/printers/") != NULL ||
+              strstr(p->device_uri, "/classes/") != NULL)) ||
+            ((strstr(p->device_uri, "._ipp.") != NULL ||
+              strstr(p->device_uri, "._ipps.") != NULL) &&
+             !strcmp(p->device_uri + strlen(p->device_uri) - 5, "/cups")))
     {
      /*
       * Tell the client this is really a hard-wired remote printer.
@@ -4887,81 +4850,6 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
 }
 
 
-/*
- * 'log_ipp_conformance()' - Log an IPP conformance issue with a printer.
- */
-
-static void
-log_ipp_conformance(
-    cupsd_printer_t *p,                        /* I - Printer */
-    const char      *reason)           /* I - Printer state reason */
-{
-  const char   *message;               /* Message to log */
-#ifdef __APPLE__
-  aslmsg       aslm;                   /* Apple System Log message */
-#endif /* __APPLE__ */
-
-
- /*
-  * Strip the leading "cups-ipp-" from the reason and create a log message for
-  * it...
-  */
-
-  reason += 9;
-  if (!strcmp(reason, "missing-cancel-job"))
-    message = "Printer does not support REQUIRED Cancel-Job operation.";
-  else if (!strcmp(reason, "missing-get-job-attributes"))
-    message = "Printer does not support REQUIRED Get-Job-Attributes operation.";
-  else if (!strcmp(reason, "missing-print-job"))
-    message = "Printer does not support REQUIRED Print-Job operation.";
-  else if (!strcmp(reason, "missing-validate-job"))
-    message = "Printer does not support REQUIRED Validate-Job operation.";
-  else if (!strcmp(reason, "missing-get-printer-attributes"))
-    message = "Printer does not support REQUIRED Get-Printer-Attributes operation.";
-  else if (!strcmp(reason, "missing-job-history"))
-    message = "Printer does not provide REQUIRED job history.";
-  else if (!strcmp(reason, "missing-job-id"))
-    message = "Printer does not provide REQUIRED job-id attribute.";
-  else if (!strcmp(reason, "missing-job-state"))
-    message = "Printer does not provide REQUIRED job-state attribute.";
-  else if (!strcmp(reason, "missing-operations-supported"))
-    message = "Printer does not provide REQUIRED operations-supported "
-              "attribute.";
-  else if (!strcmp(reason, "missing-printer-is-accepting-jobs"))
-    message = "Printer does not provide REQUIRED printer-is-accepting-jobs "
-              "attribute.";
-  else if (!strcmp(reason, "missing-printer-state-reasons"))
-    message = "Printer does not provide REQUIRED printer-state-reasons "
-              "attribute.";
-  else if (!strcmp(reason, "wrong-http-version"))
-    message = "Printer does not use REQUIRED HTTP/1.1 transport.";
-  else
-    message = "Unknown IPP conformance failure.";
-
-  cupsdLogMessage(CUPSD_LOG_WARN, "%s: %s", p->name, message);
-
-#ifdef __APPLE__
- /*
-  * Report the failure information to Apple if the user opts into providing
-  * feedback to Apple...
-  */
-
-  aslm = asl_new(ASL_TYPE_MSG);
-  if (aslm)
-  {
-    asl_set(aslm, "com.apple.message.domain", "com.apple.printing.ipp.conformance");
-    asl_set(aslm, "com.apple.message.domain_scope", "com.apple.printing.ipp.conformance");
-    asl_set(aslm, "com.apple.message.signature", reason);
-    asl_set(aslm, "com.apple.message.signature2",
-           p->make_model ? p->make_model : "Unknown");
-    asl_log(NULL, aslm, ASL_LEVEL_NOTICE, "%s: %s",
-            p->make_model ? p->make_model : "Unknown", message);
-    asl_free(aslm);
-  }
-#endif /* __APPLE__ */
-}
-
-
 /*
  * 'new_media_col()' - Create a media-col collection value.
  */
@@ -5006,261 +4894,6 @@ new_media_col(_pwg_size_t *size,        /* I - media-size/margin values */
 }
 
 
-#ifdef __sgi
-/*
- * 'write_irix_config()' - Update the config files used by the IRIX
- *                         desktop tools.
- */
-
-static void
-write_irix_config(cupsd_printer_t *p)  /* I - Printer to update */
-{
-  char         filename[1024];         /* Interface script filename */
-  cups_file_t  *fp;                    /* Interface script file */
-  ipp_attribute_t *attr;               /* Attribute data */
-
-
- /*
-  * Add dummy interface and GUI scripts to fool SGI's "challenged" printing
-  * tools.  First the interface script that tells the tools what kind of
-  * printer we have...
-  */
-
-  snprintf(filename, sizeof(filename), "/var/spool/lp/interface/%s", p->name);
-
-  if (p->type & CUPS_PRINTER_CLASS)
-    unlink(filename);
-  else if ((fp = cupsFileOpen(filename, "w")) != NULL)
-  {
-    cupsFilePuts(fp, "#!/bin/sh\n");
-
-    if ((attr = ippFindAttribute(p->attrs, "printer-make-and-model",
-                                 IPP_TAG_TEXT)) != NULL)
-      cupsFilePrintf(fp, "NAME=\"%s\"\n", attr->values[0].string.text);
-    else if (p->type & CUPS_PRINTER_CLASS)
-      cupsFilePuts(fp, "NAME=\"Printer Class\"\n");
-    else
-      cupsFilePuts(fp, "NAME=\"Remote Destination\"\n");
-
-    if (p->type & CUPS_PRINTER_COLOR)
-      cupsFilePuts(fp, "TYPE=ColorPostScript\n");
-    else
-      cupsFilePuts(fp, "TYPE=MonoPostScript\n");
-
-    cupsFilePrintf(fp, "HOSTNAME=%s\n", ServerName);
-    cupsFilePrintf(fp, "HOSTPRINTER=%s\n", p->name);
-
-    cupsFileClose(fp);
-
-    chmod(filename, 0755);
-    chown(filename, User, Group);
-  }
-
- /*
-  * Then the member file that tells which device file the queue is connected
-  * to...  Networked printers use "/dev/null" in this file, so that's what
-  * we use (the actual device URI can confuse some apps...)
-  */
-
-  snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
-
-  if (p->type & CUPS_PRINTER_CLASS)
-    unlink(filename);
-  else if ((fp = cupsFileOpen(filename, "w")) != NULL)
-  {
-    cupsFilePuts(fp, "/dev/null\n");
-
-    cupsFileClose(fp);
-
-    chmod(filename, 0644);
-    chown(filename, User, Group);
-  }
-
- /*
-  * The gui_interface file is a script or program that launches a GUI
-  * option panel for the printer, using options specified on the
-  * command-line in the third argument.  The option panel must send
-  * any printing options to stdout on a single line when the user
-  * accepts them, or nothing if the user cancels the dialog.
-  *
-  * The default options panel program is /usr/bin/glpoptions, from
-  * the ESP Print Pro software.  You can select another using the
-  * PrintcapGUI option.
-  */
-
-  snprintf(filename, sizeof(filename), "/var/spool/lp/gui_interface/ELF/%s.gui", p->name);
-
-  if (p->type & CUPS_PRINTER_CLASS)
-    unlink(filename);
-  else if ((fp = cupsFileOpen(filename, "w")) != NULL)
-  {
-    cupsFilePuts(fp, "#!/bin/sh\n");
-    cupsFilePrintf(fp, "%s -d %s -o \"$3\"\n", PrintcapGUI, p->name);
-
-    cupsFileClose(fp);
-
-    chmod(filename, 0755);
-    chown(filename, User, Group);
-  }
-
- /*
-  * The POD config file is needed by the printstatus command to show
-  * the printer location and device.
-  */
-
-  snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
-
-  if (p->type & CUPS_PRINTER_CLASS)
-    unlink(filename);
-  else if ((fp = cupsFileOpen(filename, "w")) != NULL)
-  {
-    cupsFilePrintf(fp, "Printer Class      | %s\n",
-            (p->type & CUPS_PRINTER_COLOR) ? "ColorPostScript" : "MonoPostScript");
-    cupsFilePrintf(fp, "Printer Model      | %s\n", p->make_model ? p->make_model : "");
-    cupsFilePrintf(fp, "Location Code      | %s\n", p->location ? p->location : "");
-    cupsFilePrintf(fp, "Physical Location  | %s\n", p->info ? p->info : "");
-    cupsFilePrintf(fp, "Port Path          | %s\n", p->device_uri);
-    cupsFilePrintf(fp, "Config Path        | /var/spool/lp/pod/%s.config\n", p->name);
-    cupsFilePrintf(fp, "Active Status Path | /var/spool/lp/pod/%s.status\n", p->name);
-    cupsFilePuts(fp, "Status Update Wait | 10 seconds\n");
-
-    cupsFileClose(fp);
-
-    chmod(filename, 0664);
-    chown(filename, User, Group);
-  }
-}
-
-
-/*
- * 'write_irix_state()' - Update the status files used by IRIX printing
- *                        desktop tools.
- */
-
-static void
-write_irix_state(cupsd_printer_t *p)   /* I - Printer to update */
-{
-  char         filename[1024];         /* Interface script filename */
-  cups_file_t  *fp;                    /* Interface script file */
-  int          tag;                    /* Status tag value */
-
-
-  if (p)
-  {
-   /*
-    * The POD status file is needed for the printstatus window to
-    * provide the current status of the printer.
-    */
-
-    snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
-
-    if (p->type & CUPS_PRINTER_CLASS)
-      unlink(filename);
-    else if ((fp = cupsFileOpen(filename, "w")) != NULL)
-    {
-      cupsFilePrintf(fp, "Operational Status | %s\n",
-              (p->state == IPP_PRINTER_IDLE)       ? "Idle" :
-              (p->state == IPP_PRINTER_PROCESSING) ? "Busy" :
-                                                     "Faulted");
-      cupsFilePrintf(fp, "Information        | 01 00 00 | %s\n", CUPS_SVERSION);
-      cupsFilePrintf(fp, "Information        | 02 00 00 | Device URI: %s\n",
-              p->device_uri);
-      cupsFilePrintf(fp, "Information        | 03 00 00 | %s jobs\n",
-              p->accepting ? "Accepting" : "Not accepting");
-      cupsFilePrintf(fp, "Information        | 04 00 00 | %s\n", p->state_message);
-
-      cupsFileClose(fp);
-
-      chmod(filename, 0664);
-      chown(filename, User, Group);
-    }
-
-   /*
-    * The activeicons file is needed to provide desktop icons for printers:
-    *
-    * [ quoted from /usr/lib/print/tagit ]
-    *
-    * --- Type of printer tags (base values)
-    *
-    * Dumb=66048                       # 0x10200
-    * DumbColor=66080          # 0x10220
-    * Raster=66112             # 0x10240
-    * ColorRaster=66144                # 0x10260
-    * Plotter=66176            # 0x10280
-    * PostScript=66208         # 0x102A0
-    * ColorPostScript=66240    # 0x102C0
-    * MonoPostScript=66272     # 0x102E0
-    *
-    * --- Printer state modifiers for local printers
-    *
-    * Idle=0                   # 0x0
-    * Busy=1                   # 0x1
-    * Faulted=2                        # 0x2
-    * Unknown=3                        # 0x3 (Faulted due to unknown reason)
-    *
-    * --- Printer state modifiers for network printers
-    *
-    * NetIdle=8                        # 0x8
-    * NetBusy=9                        # 0x9
-    * NetFaulted=10            # 0xA
-    * NetUnknown=11            # 0xB (Faulted due to unknown reason)
-    */
-
-    snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
-
-    if (p->type & CUPS_PRINTER_CLASS)
-      unlink(filename);
-    else if ((fp = cupsFileOpen(filename, "w")) != NULL)
-    {
-      if (p->type & CUPS_PRINTER_COLOR)
-       tag = 66240;
-      else
-       tag = 66272;
-
-      if (p->type & CUPS_PRINTER_REMOTE)
-       tag |= 8;
-
-      if (p->state == IPP_PRINTER_PROCESSING)
-       tag |= 1;
-
-      else if (p->state == IPP_PRINTER_STOPPED)
-       tag |= 2;
-
-      cupsFilePuts(fp, "#!/bin/sh\n");
-      cupsFilePrintf(fp, "#Tag %d\n", tag);
-
-      cupsFileClose(fp);
-
-      chmod(filename, 0755);
-      chown(filename, User, Group);
-    }
-  }
-
- /*
-  * The default file is needed by the printers window to show
-  * the default printer.
-  */
-
-  snprintf(filename, sizeof(filename), "/var/spool/lp/default");
-
-  if (DefaultPrinter != NULL)
-  {
-    if ((fp = cupsFileOpen(filename, "w")) != NULL)
-    {
-      cupsFilePrintf(fp, "%s\n", DefaultPrinter->name);
-
-      cupsFileClose(fp);
-
-      chmod(filename, 0644);
-      chown(filename, User, Group);
-    }
-  }
-  else
-    unlink(filename);
-}
-#endif /* __sgi */
-
-
 /*
  * 'write_xml_string()' - Write a string with XML escaping.
  */
@@ -5280,7 +4913,7 @@ write_xml_string(cups_file_t *fp, /* I - File to write to */
     if (*s == '&')
     {
       if (s > start)
-        cupsFileWrite(fp, start, s - start);
+        cupsFileWrite(fp, start, (size_t)(s - start));
 
       cupsFilePuts(fp, "&amp;");
       start = s + 1;
@@ -5288,7 +4921,7 @@ write_xml_string(cups_file_t *fp, /* I - File to write to */
     else if (*s == '<')
     {
       if (s > start)
-        cupsFileWrite(fp, start, s - start);
+        cupsFileWrite(fp, start, (size_t)(s - start));
 
       cupsFilePuts(fp, "&lt;");
       start = s + 1;
@@ -5301,5 +4934,5 @@ write_xml_string(cups_file_t *fp, /* I - File to write to */
 
 
 /*
- * End of "$Id: printers.c 7968 2008-09-19 23:03:01Z mike $".
+ * End of "$Id$".
  */