]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/printers.c
Merge changes from CUPS 1.6svn-r10437.
[thirdparty/cups.git] / scheduler / printers.c
index b04b75646ab055ce9f6a00e3d99d16c9d5d9f225..0119342326fd680d123303d5a1b1993c5b7d8569 100644 (file)
@@ -3,7 +3,7 @@
  *
  *   Printer routines for the CUPS scheduler.
  *
- *   Copyright 2007-2011 by Apple Inc.
+ *   Copyright 2007-2012 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
@@ -15,7 +15,6 @@
  * Contents:
  *
  *   cupsdAddPrinter()          - Add a printer to the system.
- *   cupsdAddPrinterHistory()   - Add the current printer state to the history.
  *   cupsdCreateCommonData()    - Create the common printer data.
  *   cupsdDeleteAllPrinters()   - Delete all printers from the system.
  *   cupsdDeletePrinter()       - Delete a printer from the system.
  *   add_printer_filter()       - Add a MIME filter for a printer.
  *   add_printer_formats()      - Add document-format-supported values for a
  *                                printer.
- *   add_string_array()         - Add a string to an array of CUPS strings.
  *   compare_printers()         - Compare two printers.
  *   delete_printer_filters()   - Delete all MIME filters for a printer.
- *   delete_string_array()      - Delete an array of CUPS strings.
  *   dirty_printer()            - Mark config and state files dirty for the
  *                                specified printer.
  *   load_ppd()                 - Load a cached PPD file, updating the cache as
@@ -79,6 +76,9 @@
 #ifdef HAVE_SYS_VFS_H
 #  include <sys/vfs.h>
 #endif /* HAVE_SYS_VFS_H */
+#ifdef __APPLE__
+#  include <asl.h>
+#endif /* __APPLE__ */
 
 
 /*
@@ -89,12 +89,11 @@ static void add_printer_defaults(cupsd_printer_t *p);
 static void    add_printer_filter(cupsd_printer_t *p, mime_type_t *type,
                                   const char *filter);
 static void    add_printer_formats(cupsd_printer_t *p);
-static void    add_string_array(cups_array_t **a, const char *s);
 static int     compare_printers(void *first, void *second, void *data);
 static void    delete_printer_filters(cupsd_printer_t *p);
-static void    delete_string_array(cups_array_t **a);
 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
@@ -112,7 +111,8 @@ cupsd_printer_t *                   /* O - New printer */
 cupsdAddPrinter(const char *name)      /* I - Name of printer */
 {
   cupsd_printer_t      *p;             /* New printer */
-  char                 uri[1024];      /* Printer URI */
+  char                 uri[1024],      /* Printer URI */
+                       uuid[64];       /* Printer UUID */
 
 
  /*
@@ -139,6 +139,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)));
   cupsdSetDeviceURI(p, "file:///dev/null");
 
   p->state      = IPP_PRINTER_STOPPED;
@@ -155,9 +157,6 @@ cupsdAddPrinter(const char *name)   /* I - Name of printer */
 
   p->op_policy_ptr = DefaultPolicyPtr;
 
-  if (MaxPrinterHistory)
-    p->history = calloc(MaxPrinterHistory, sizeof(ipp_t *));
-
  /*
   * Insert the printer in the printer list alphabetically...
   */
@@ -169,9 +168,6 @@ cupsdAddPrinter(const char *name)   /* I - Name of printer */
                   "cupsdAddPrinter: Adding %s to Printers", p->name);
   cupsArrayAdd(Printers, p);
 
-  if (!ImplicitPrinters)
-    ImplicitPrinters = cupsArrayNew(compare_printers, NULL);
-
  /*
   * Return the new printer...
   */
@@ -180,67 +176,6 @@ cupsdAddPrinter(const char *name)  /* I - Name of printer */
 }
 
 
-/*
- * 'cupsdAddPrinterHistory()' - Add the current printer state to the history.
- */
-
-void
-cupsdAddPrinterHistory(
-    cupsd_printer_t *p)                        /* I - Printer */
-{
-  ipp_t        *history;                       /* History collection */
-
-
- /*
-  * Stop early if we aren't keeping history data...
-  */
-
-  if (MaxPrinterHistory <= 0)
-    return;
-
- /*
-  * Retire old history data as needed...
-  */
-
-  p->sequence_number ++;
-
-  if (p->num_history >= MaxPrinterHistory)
-  {
-    p->num_history --;
-    ippDelete(p->history[0]);
-    memmove(p->history, p->history + 1, p->num_history * sizeof(ipp_t *));
-  }
-
- /*
-  * Create a collection containing the current printer-state, printer-up-time,
-  * printer-state-message, and printer-state-reasons attributes.
-  */
-
-  history = ippNew();
-  ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state",
-                p->state);
-  ippAddBoolean(history, IPP_TAG_PRINTER, "printer-is-accepting-jobs",
-                p->accepting);
-  ippAddBoolean(history, IPP_TAG_PRINTER, "printer-is-shared", p->shared);
-  ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-state-message",
-               NULL, p->state_message);
-  if (p->num_reasons == 0)
-    ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                 "printer-state-reasons", NULL, "none");
-  else
-    ippAddStrings(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                  "printer-state-reasons", p->num_reasons, NULL,
-                 (const char * const *)p->reasons);
-  ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-                "printer-state-change-time", p->state_time);
-  ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-                "printer-state-sequence-number", p->sequence_number);
-
-  p->history[p->num_history] = history;
-  p->num_history ++;
-}
-
-
 /*
  * 'cupsdCreateCommonData()' - Create the common printer data.
  */
@@ -439,6 +374,18 @@ cupsdCreateCommonData(void)
                  "printer-resolution",
                  "sides"
                };
+  static const char * const pdf_versions[] =
+               {                       /* pdf-versions-supported */
+                 "adobe-1.2",
+                 "adobe-1.3",
+                 "adobe-1.4",
+                 "adobe-1.5",
+                 "adobe-1.6",
+                 "adobe-1.7",
+                 "iso-19005-1_2005",
+                 "iso-32000-1_2008",
+                 "pwg-5102.3"
+               };
   static const char * const printer_settable[] =
                {                       /* printer-settable-attributes-supported */
                  "printer-info",
@@ -546,8 +493,8 @@ cupsdCreateCommonData(void)
   ippAddBoolean(CommonData, IPP_TAG_PRINTER, "job-ids-supported", 1);
 
   /* job-k-octets-supported */
-  ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-                "job-k-octets-supported", k_supported);
+  ippAddRange(CommonData, IPP_TAG_PRINTER, "job-k-octets-supported", 0,
+              k_supported);
 
   /* job-priority-supported */
   ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
@@ -597,6 +544,18 @@ cupsdCreateCommonData(void)
     ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
                  "job-sheets-supported", NULL, "none");
 
+  /* jpeg-k-octets-supported */
+  ippAddRange(CommonData, IPP_TAG_PRINTER, "jpeg-k-octets-supported", 0,
+              k_supported);
+
+  /* jpeg-x-dimension-supported */
+  ippAddRange(CommonData, IPP_TAG_PRINTER, "jpeg-x-dimension-supported", 0,
+              65535);
+
+  /* jpeg-y-dimension-supported */
+  ippAddRange(CommonData, IPP_TAG_PRINTER, "jpeg-y-dimension-supported", 1,
+              65535);
+
   /* media-col-supported */
   ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
                 "media-col-supported",
@@ -681,8 +640,7 @@ cupsdCreateCommonData(void)
 
   /* operations-supported */
   ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
-                 "operations-supported",
-                 sizeof(ops) / sizeof(ops[0]) + JobFiles - 1, ops);
+                 "operations-supported", sizeof(ops) / sizeof(ops[0]), ops);
 
   /* orientation-requested-supported */
   ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
@@ -691,6 +649,16 @@ cupsdCreateCommonData(void)
   /* page-ranges-supported */
   ippAddBoolean(CommonData, IPP_TAG_PRINTER, "page-ranges-supported", 1);
 
+  /* pdf-k-octets-supported */
+  ippAddRange(CommonData, IPP_TAG_PRINTER, "pdf-k-octets-supported", 0,
+              k_supported);
+
+  /* pdf-versions-supported */
+  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+                "pdf-versions-supported",
+                sizeof(pdf_versions) / sizeof(pdf_versions[0]), NULL,
+                pdf_versions);
+
   /* pdl-override-supported */
   ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
                "pdl-override-supported", NULL, "attempted");
@@ -779,16 +747,6 @@ cupsdDeletePrinter(
                      update ? "Job stopped due to printer being deleted." :
                              "Job stopped.");
 
- /*
-  * If this printer is the next for browsing, point to the next one...
-  */
-
-  if (p == BrowseNext)
-  {
-    cupsArrayFind(Printers, p);
-    BrowseNext = (cupsd_printer_t *)cupsArrayNext(Printers);
-  }
-
  /*
   * Remove the printer from the list...
   */
@@ -797,14 +755,6 @@ cupsdDeletePrinter(
                   "cupsdDeletePrinter: Removing %s from Printers", p->name);
   cupsArrayRemove(Printers, p);
 
-  if (p->type & CUPS_PRINTER_IMPLICIT)
-  {
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                   "cupsdDeletePrinter: Removing %s from ImplicitPrinters",
-                   p->name);
-    cupsArrayRemove(ImplicitPrinters, p);
-  }
-
  /*
   * Remove the dummy interface/icon/option files under IRIX...
   */
@@ -835,43 +785,19 @@ cupsdDeletePrinter(
   */
 
   if (p == DefaultPrinter)
-  {
     DefaultPrinter = NULL;
 
-    if (UseNetworkDefault)
-    {
-     /*
-      * Find the first network default printer and use it...
-      */
-
-      cupsd_printer_t  *dp;            /* New default printer */
-
-
-      for (dp = (cupsd_printer_t *)cupsArrayFirst(Printers);
-          dp;
-          dp = (cupsd_printer_t *)cupsArrayNext(Printers))
-       if (dp != p && (dp->type & CUPS_PRINTER_DEFAULT))
-       {
-         DefaultPrinter = dp;
-         break;
-       }
-    }
-  }
-
  /*
   * Remove this printer from any classes...
   */
 
-  if (!(p->type & CUPS_PRINTER_IMPLICIT))
-  {
-    changed = cupsdDeletePrinterFromClasses(p);
+  changed = cupsdDeletePrinterFromClasses(p);
 
  /*
-    * Deregister from any browse protocols...
-    */
+ /*
+  * Deregister from any browse protocols...
+  */
 
-    cupsdDeregisterPrinter(p, 1);
-  }
+  cupsdDeregisterPrinter(p, 1);
 
  /*
   * Free all memory used by the printer...
@@ -880,14 +806,6 @@ cupsdDeletePrinter(
   if (p->printers != NULL)
     free(p->printers);
 
-  if (MaxPrinterHistory)
-  {
-    for (i = 0; i < p->num_history; i ++)
-      ippDelete(p->history[i]);
-
-    free(p->history);
-  }
-
   delete_printer_filters(p);
 
   for (i = 0; i < p->num_reasons; i ++)
@@ -899,9 +817,6 @@ cupsdDeletePrinter(
   mimeDeleteType(MimeDatabase, p->filetype);
   mimeDeleteType(MimeDatabase, p->prefiltertype);
 
-  delete_string_array(&(p->filters));
-  delete_string_array(&(p->pre_filters));
-
   cupsdFreeStrings(&(p->users));
   cupsdFreeQuotas(p);
 
@@ -922,16 +837,13 @@ cupsdDeletePrinter(
   cupsdClearString(&p->alert);
   cupsdClearString(&p->alert_description);
 
-#ifdef HAVE_DNSSD
-  cupsdClearString(&p->product);
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
   cupsdClearString(&p->pdl);
-#endif /* HAVE_DNSSD */
+  cupsdClearString(&p->reg_name);
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
 
   cupsArrayDelete(p->filetypes);
 
-  if (p->browse_attrs)
-    free(p->browse_attrs);
-
   cupsFreeOptions(p->num_options, p->options);
 
   free(p);
@@ -999,13 +911,8 @@ cupsdLoadAllPrinters(void)
   */
 
   snprintf(line, sizeof(line), "%s/printers.conf", ServerRoot);
-  if ((fp = cupsFileOpen(line, "r")) == NULL)
-  {
-    if (errno != ENOENT)
-      cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open %s - %s", line,
-                     strerror(errno));
+  if ((fp = cupsdOpenConfFile(line)) == NULL)
     return;
-  }
 
  /*
   * Read printer configurations until we hit EOF...
@@ -1020,8 +927,8 @@ cupsdLoadAllPrinters(void)
     * Decode the directive...
     */
 
-    if (!strcasecmp(line, "<Printer") ||
-        !strcasecmp(line, "<DefaultPrinter"))
+    if (!_cups_strcasecmp(line, "<Printer") ||
+        !_cups_strcasecmp(line, "<DefaultPrinter"))
     {
      /*
       * <Printer name> or <DefaultPrinter name>
@@ -1043,14 +950,14 @@ cupsdLoadAllPrinters(void)
         * Set the default printer as needed...
        */
 
-        if (!strcasecmp(line, "<DefaultPrinter"))
+        if (!_cups_strcasecmp(line, "<DefaultPrinter"))
          DefaultPrinter = p;
       }
       else
         cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Syntax error on line %d of printers.conf.", linenum);
     }
-    else if (!strcasecmp(line, "</Printer>"))
+    else if (!_cups_strcasecmp(line, "</Printer>"))
     {
       if (p != NULL)
       {
@@ -1059,7 +966,6 @@ cupsdLoadAllPrinters(void)
        */
 
         cupsdSetPrinterAttrs(p);
-       cupsdAddPrinterHistory(p);
 
         if (strncmp(p->device_uri, "file:", 5) &&
            p->state != IPP_PRINTER_STOPPED)
@@ -1097,29 +1003,37 @@ cupsdLoadAllPrinters(void)
       cupsdLogMessage(CUPSD_LOG_ERROR,
                       "Syntax error on line %d of printers.conf.", linenum);
     }
-    else if (!strcasecmp(line, "AuthInfoRequired"))
+    else if (!_cups_strcasecmp(line, "UUID"))
+    {
+      if (value && !strncmp(value, "urn:uuid:", 9))
+        cupsdSetString(&(p->uuid), value);
+      else
+        cupsdLogMessage(CUPSD_LOG_ERROR,
+                       "Bad UUID on line %d of printers.conf.", linenum);
+    }
+    else if (!_cups_strcasecmp(line, "AuthInfoRequired"))
     {
       if (!cupsdSetAuthInfoRequired(p, value, NULL))
        cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Bad AuthInfoRequired on line %d of printers.conf.",
                        linenum);
     }
-    else if (!strcasecmp(line, "Info"))
+    else if (!_cups_strcasecmp(line, "Info"))
     {
       if (value)
        cupsdSetString(&p->info, value);
     }
-    else if (!strcasecmp(line, "MakeModel"))
+    else if (!_cups_strcasecmp(line, "MakeModel"))
     {
       if (value)
        cupsdSetString(&p->make_model, value);
     }
-    else if (!strcasecmp(line, "Location"))
+    else if (!_cups_strcasecmp(line, "Location"))
     {
       if (value)
        cupsdSetString(&p->location, value);
     }
-    else if (!strcasecmp(line, "DeviceURI"))
+    else if (!_cups_strcasecmp(line, "DeviceURI"))
     {
       if (value)
        cupsdSetDeviceURI(p, value);
@@ -1127,7 +1041,7 @@ cupsdLoadAllPrinters(void)
        cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Syntax error on line %d of printers.conf.", linenum);
     }
-    else if (!strcasecmp(line, "Option") && value)
+    else if (!_cups_strcasecmp(line, "Option") && value)
     {
      /*
       * Option name value
@@ -1146,7 +1060,7 @@ cupsdLoadAllPrinters(void)
                                       &(p->options));
       }
     }
-    else if (!strcasecmp(line, "PortMonitor"))
+    else if (!_cups_strcasecmp(line, "PortMonitor"))
     {
       if (value && strcmp(value, "none"))
        cupsdSetString(&p->port_monitor, value);
@@ -1156,7 +1070,7 @@ cupsdLoadAllPrinters(void)
        cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Syntax error on line %d of printers.conf.", linenum);
     }
-    else if (!strcasecmp(line, "Reason"))
+    else if (!_cups_strcasecmp(line, "Reason"))
     {
       if (value &&
           strcmp(value, "connecting-to-device") &&
@@ -1178,15 +1092,15 @@ cupsdLoadAllPrinters(void)
        cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Syntax error on line %d of printers.conf.", linenum);
     }
-    else if (!strcasecmp(line, "State"))
+    else if (!_cups_strcasecmp(line, "State"))
     {
      /*
       * Set the initial queue state...
       */
 
-      if (value && !strcasecmp(value, "idle"))
+      if (value && !_cups_strcasecmp(value, "idle"))
         p->state = IPP_PRINTER_IDLE;
-      else if (value && !strcasecmp(value, "stopped"))
+      else if (value && !_cups_strcasecmp(value, "stopped"))
       {
         p->state = IPP_PRINTER_STOPPED;
 
@@ -1205,7 +1119,7 @@ cupsdLoadAllPrinters(void)
        cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Syntax error on line %d of printers.conf.", linenum);
     }
-    else if (!strcasecmp(line, "StateMessage"))
+    else if (!_cups_strcasecmp(line, "StateMessage"))
     {
      /*
       * Set the initial queue state message...
@@ -1214,7 +1128,7 @@ cupsdLoadAllPrinters(void)
       if (value)
        strlcpy(p->state_message, value, sizeof(p->state_message));
     }
-    else if (!strcasecmp(line, "StateTime"))
+    else if (!_cups_strcasecmp(line, "StateTime"))
     {
      /*
       * Set the state time...
@@ -1223,27 +1137,27 @@ cupsdLoadAllPrinters(void)
       if (value)
         p->state_time = atoi(value);
     }
-    else if (!strcasecmp(line, "Accepting"))
+    else if (!_cups_strcasecmp(line, "Accepting"))
     {
      /*
       * Set the initial accepting state...
       */
 
       if (value &&
-          (!strcasecmp(value, "yes") ||
-           !strcasecmp(value, "on") ||
-           !strcasecmp(value, "true")))
+          (!_cups_strcasecmp(value, "yes") ||
+           !_cups_strcasecmp(value, "on") ||
+           !_cups_strcasecmp(value, "true")))
         p->accepting = 1;
       else if (value &&
-               (!strcasecmp(value, "no") ||
-               !strcasecmp(value, "off") ||
-               !strcasecmp(value, "false")))
+               (!_cups_strcasecmp(value, "no") ||
+               !_cups_strcasecmp(value, "off") ||
+               !_cups_strcasecmp(value, "false")))
         p->accepting = 0;
       else
        cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Syntax error on line %d of printers.conf.", linenum);
     }
-    else if (!strcasecmp(line, "Type"))
+    else if (!_cups_strcasecmp(line, "Type"))
     {
       if (value)
         p->type = atoi(value);
@@ -1251,65 +1165,27 @@ cupsdLoadAllPrinters(void)
        cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Syntax error on line %d of printers.conf.", linenum);
     }
-    else if (!strcasecmp(line, "Product"))
-    {
-      if (value)
-      {
-#ifdef HAVE_DNSSD
-        p->product = _cupsStrAlloc(value);
-#endif /* HAVE_DNSSD */
-      }
-      else
-       cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "Syntax error on line %d of printers.conf.", linenum);
-    }
-    else if (!strcasecmp(line, "Filter"))
-    {
-      if (value)
-      {
-        if (!p->filters)
-         p->filters = cupsArrayNew(NULL, NULL);
-
-       cupsArrayAdd(p->filters, _cupsStrAlloc(value));
-      }
-      else
-       cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "Syntax error on line %d of printers.conf.", linenum);
-    }
-    else if (!strcasecmp(line, "PreFilter"))
-    {
-      if (value)
-      {
-        if (!p->pre_filters)
-         p->pre_filters = cupsArrayNew(NULL, NULL);
-
-       cupsArrayAdd(p->pre_filters, _cupsStrAlloc(value));
-      }
-      else
-       cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "Syntax error on line %d of printers.conf.", linenum);
-    }
-    else if (!strcasecmp(line, "Shared"))
+    else if (!_cups_strcasecmp(line, "Shared"))
     {
      /*
       * Set the initial shared state...
       */
 
       if (value &&
-          (!strcasecmp(value, "yes") ||
-           !strcasecmp(value, "on") ||
-           !strcasecmp(value, "true")))
+          (!_cups_strcasecmp(value, "yes") ||
+           !_cups_strcasecmp(value, "on") ||
+           !_cups_strcasecmp(value, "true")))
         p->shared = 1;
       else if (value &&
-               (!strcasecmp(value, "no") ||
-               !strcasecmp(value, "off") ||
-               !strcasecmp(value, "false")))
+               (!_cups_strcasecmp(value, "no") ||
+               !_cups_strcasecmp(value, "off") ||
+               !_cups_strcasecmp(value, "false")))
         p->shared = 0;
       else
        cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Syntax error on line %d of printers.conf.", linenum);
     }
-    else if (!strcasecmp(line, "JobSheets"))
+    else if (!_cups_strcasecmp(line, "JobSheets"))
     {
      /*
       * Set the initial job sheets...
@@ -1341,7 +1217,7 @@ cupsdLoadAllPrinters(void)
        cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Syntax error on line %d of printers.conf.", linenum);
     }
-    else if (!strcasecmp(line, "AllowUser"))
+    else if (!_cups_strcasecmp(line, "AllowUser"))
     {
       if (value)
       {
@@ -1352,7 +1228,7 @@ cupsdLoadAllPrinters(void)
        cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Syntax error on line %d of printers.conf.", linenum);
     }
-    else if (!strcasecmp(line, "DenyUser"))
+    else if (!_cups_strcasecmp(line, "DenyUser"))
     {
       if (value)
       {
@@ -1363,7 +1239,7 @@ cupsdLoadAllPrinters(void)
        cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Syntax error on line %d of printers.conf.", linenum);
     }
-    else if (!strcasecmp(line, "QuotaPeriod"))
+    else if (!_cups_strcasecmp(line, "QuotaPeriod"))
     {
       if (value)
         p->quota_period = atoi(value);
@@ -1371,7 +1247,7 @@ cupsdLoadAllPrinters(void)
        cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Syntax error on line %d of printers.conf.", linenum);
     }
-    else if (!strcasecmp(line, "PageLimit"))
+    else if (!_cups_strcasecmp(line, "PageLimit"))
     {
       if (value)
         p->page_limit = atoi(value);
@@ -1379,7 +1255,7 @@ cupsdLoadAllPrinters(void)
        cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Syntax error on line %d of printers.conf.", linenum);
     }
-    else if (!strcasecmp(line, "KLimit"))
+    else if (!_cups_strcasecmp(line, "KLimit"))
     {
       if (value)
         p->k_limit = atoi(value);
@@ -1387,7 +1263,7 @@ cupsdLoadAllPrinters(void)
        cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Syntax error on line %d of printers.conf.", linenum);
     }
-    else if (!strcasecmp(line, "OpPolicy"))
+    else if (!_cups_strcasecmp(line, "OpPolicy"))
     {
       if (value)
       {
@@ -1408,7 +1284,7 @@ cupsdLoadAllPrinters(void)
        cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Syntax error on line %d of printers.conf.", linenum);
     }
-    else if (!strcasecmp(line, "ErrorPolicy"))
+    else if (!_cups_strcasecmp(line, "ErrorPolicy"))
     {
       if (value)
         cupsdSetString(&p->error_policy, value);
@@ -1416,7 +1292,7 @@ cupsdLoadAllPrinters(void)
        cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Syntax error on line %d of printers.conf.", linenum);
     }
-    else if (!strcasecmp(line, "Attribute") && value)
+    else if (!_cups_strcasecmp(line, "Attribute") && value)
     {
       for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);
 
@@ -1436,15 +1312,18 @@ cupsdLoadAllPrinters(void)
           cupsdSetPrinterAttr(p, value, valueptr);
       }
     }
-    else
+    else if (_cups_strcasecmp(line, "Filter") &&
+             _cups_strcasecmp(line, "Prefilter") &&
+             _cups_strcasecmp(line, "Product"))
     {
      /*
-      * Something else we don't understand...
+      * Something else we don't understand (and that wasn't used in a prior
+      * release of CUPS...
       */
 
       cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "Unknown configuration directive %s on line %d of printers.conf.",
-                     line, linenum);
+                      "Unknown configuration directive %s on line %d of "
+                     "printers.conf.", line, linenum);
     }
   }
 
@@ -1469,14 +1348,6 @@ cupsdRenamePrinter(
                   "cupsdRenamePrinter: Removing %s from Printers", p->name);
   cupsArrayRemove(Printers, p);
 
-  if (p->type & CUPS_PRINTER_IMPLICIT)
-  {
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                   "cupsdRenamePrinter: Removing %s from ImplicitPrinters",
-                   p->name);
-    cupsArrayRemove(ImplicitPrinters, p);
-  }
-
  /*
   * Rename the printer type...
   */
@@ -1484,8 +1355,11 @@ cupsdRenamePrinter(
   mimeDeleteType(MimeDatabase, p->filetype);
   p->filetype = mimeAddType(MimeDatabase, "printer", name);
 
-  mimeDeleteType(MimeDatabase, p->prefiltertype);
-  p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", name);
+  if (p->prefiltertype)
+  {
+    mimeDeleteType(MimeDatabase, p->prefiltertype);
+    p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", name);
+  }
 
  /*
   * Rename the printer...
@@ -1506,14 +1380,6 @@ cupsdRenamePrinter(
   cupsdLogMessage(CUPSD_LOG_DEBUG2,
                   "cupsdRenamePrinter: Adding %s to Printers", p->name);
   cupsArrayAdd(Printers, p);
-
-  if (p->type & CUPS_PRINTER_IMPLICIT)
-  {
-    cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                   "cupsdRenamePrinter: Adding %s to ImplicitPrinters",
-                   p->name);
-    cupsArrayAdd(ImplicitPrinters, p);
-  }
 }
 
 
@@ -1527,8 +1393,8 @@ cupsdSaveAllPrinters(void)
 {
   int                  i;              /* Looping var */
   cups_file_t          *fp;            /* printers.conf file */
-  char                 temp[1024],     /* Temporary string */
-                       backup[1024],   /* printers.conf.O file */
+  char                 filename[1024], /* printers.conf filename */
+                       temp[1024],     /* Temporary string */
                        value[2048],    /* Value string */
                        *ptr,           /* Pointer into value */
                        *name;          /* Current user/group name */
@@ -1543,35 +1409,12 @@ cupsdSaveAllPrinters(void)
   * Create the printers.conf file...
   */
 
-  snprintf(temp, sizeof(temp), "%s/printers.conf", ServerRoot);
-  snprintf(backup, sizeof(backup), "%s/printers.conf.O", ServerRoot);
+  snprintf(filename, sizeof(filename), "%s/printers.conf", ServerRoot);
 
-  if (rename(temp, backup))
-  {
-    if (errno != ENOENT)
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "Unable to backup printers.conf - %s", strerror(errno));
-  }
-
-  if ((fp = cupsFileOpen(temp, "w")) == NULL)
-  {
-    cupsdLogMessage(CUPSD_LOG_ERROR,
-                    "Unable to save printers.conf - %s", strerror(errno));
-
-    if (rename(backup, temp))
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "Unable to restore printers.conf - %s", strerror(errno));
+  if ((fp = cupsdCreateConfFile(filename, ConfigFilePerm & 0600)) == NULL)
     return;
-  }
-  else
-    cupsdLogMessage(CUPSD_LOG_INFO, "Saving printers.conf...");
 
- /*
-  * Restrict access to the file...
-  */
-
-  fchown(cupsFileNumber(fp), getuid(), Group);
-  fchmod(cupsFileNumber(fp), ConfigFilePerm & 0600);
+  cupsdLogMessage(CUPSD_LOG_INFO, "Saving printers.conf...");
 
  /*
   * Write a small header to the file...
@@ -1594,12 +1437,10 @@ cupsdSaveAllPrinters(void)
        printer = (cupsd_printer_t *)cupsArrayNext(Printers))
   {
    /*
-    * Skip remote destinations and printer classes...
+    * Skip printer classes...
     */
 
-    if ((printer->type & CUPS_PRINTER_DISCOVERED) ||
-        (printer->type & CUPS_PRINTER_CLASS) ||
-       (printer->type & CUPS_PRINTER_IMPLICIT))
+    if (printer->type & CUPS_PRINTER_CLASS)
       continue;
 
    /*
@@ -1611,6 +1452,8 @@ cupsdSaveAllPrinters(void)
     else
       cupsFilePrintf(fp, "<Printer %s>\n", printer->name);
 
+    cupsFilePrintf(fp, "UUID %s\n", printer->uuid);
+
     if (printer->num_auth_info_required > 0)
     {
       switch (printer->num_auth_info_required)
@@ -1671,21 +1514,6 @@ cupsdSaveAllPrinters(void)
 
     cupsFilePrintf(fp, "Type %d\n", printer->type);
 
-#ifdef HAVE_DNSSD
-    if (printer->product)
-      cupsFilePutConf(fp, "Product", printer->product);
-#endif /* HAVE_DNSSD */
-
-    for (ptr = (char *)cupsArrayFirst(printer->filters);
-         ptr;
-        ptr = (char *)cupsArrayNext(printer->filters))
-      cupsFilePutConf(fp, "Filter", ptr);
-
-    for (ptr = (char *)cupsArrayFirst(printer->pre_filters);
-         ptr;
-        ptr = (char *)cupsArrayNext(printer->pre_filters))
-      cupsFilePutConf(fp, "PreFilter", ptr);
-
     if (printer->accepting)
       cupsFilePuts(fp, "Accepting Yes\n");
     else
@@ -1839,7 +1667,7 @@ cupsdSaveAllPrinters(void)
 #endif /* __sgi */
   }
 
-  cupsFileClose(fp);
+  cupsdCloseCreatedConfFile(fp, filename);
 }
 
 
@@ -1893,6 +1721,16 @@ cupsdSetAuthInfoRequired(
 
         p->auth_info_required[p->num_auth_info_required] = "negotiate";
        p->num_auth_info_required ++;
+
+       /*
+        * Don't allow sharing of queues that require Kerberos authentication.
+       */
+
+       if (p->shared)
+       {
+         cupsdDeregisterPrinter(p, 1);
+         p->shared = 0;
+       }
       }
       else if ((end - values) == 6 && !strncmp(values, "domain", 6))
       {
@@ -1941,16 +1779,6 @@ cupsdSetAuthInfoRequired(
   if (!attr || attr->num_values > 4)
     return (0);
 
- /*
-  * Update the printer-type value as needed...
-  */
-
-  if (attr->num_values > 1 ||
-      strcmp(attr->values[0].string.text, "none"))
-    p->type |= CUPS_PRINTER_AUTHENTICATED;
-  else
-    p->type &= ~CUPS_PRINTER_AUTHENTICATED;
-
   for (i = 0; i < attr->num_values; i ++)
   {
     if (!strcmp(attr->values[i].string.text, "none"))
@@ -1971,6 +1799,16 @@ cupsdSetAuthInfoRequired(
       p->auth_info_required[p->num_auth_info_required] = "negotiate";
       p->num_auth_info_required ++;
 
+     /*
+      * Don't allow sharing of queues that require Kerberos authentication.
+      */
+
+      if (p->shared)
+      {
+       cupsdDeregisterPrinter(p, 1);
+       p->shared = 0;
+      }
+
       return (1);
     }
     else if (!strcmp(attr->values[i].string.text, "domain"))
@@ -2077,7 +1915,9 @@ cupsdSetPrinterAttr(
   ipp_attribute_t      *attr;          /* Attribute */
   int                  i,              /* Looping var */
                        count;          /* Number of values */
-  char                 *ptr;           /* Pointer into value */
+  char                 *ptr,           /* Pointer into value */
+                       *start,         /* Start of value */
+                       quote;          /* Quote character */
   ipp_tag_t            value_tag;      /* Value tag for this attribute */
 
 
@@ -2095,9 +1935,21 @@ cupsdSetPrinterAttr(
   * Count the number of values...
   */
 
-  for (count = 1, ptr = value;
-       (ptr = strchr(ptr, ',')) != NULL;
-       ptr ++, count ++);
+  for (count = 1, quote = '\0', ptr = value;
+       *ptr;
+       ptr ++)
+  {
+    if (*ptr == quote)
+      quote = '\0';
+    else if (quote)
+      continue;
+    else if (*ptr == '\\' && ptr[1])
+      ptr ++;
+    else if (*ptr == '\'' || *ptr == '\"')
+      quote = *ptr;
+    else if (*ptr == ',')
+      count ++;
+  }
 
  /*
   * Then add or update the attribute as needed...
@@ -2181,15 +2033,33 @@ cupsdSetPrinterAttr(
       return;
     }
 
-    for (i = 0; i < count; i ++)
+    for (i = 0, quote = '\0', ptr = value; i < count; i ++)
     {
-      if ((ptr = strchr(value, ',')) != NULL)
-        *ptr++ = '\0';
+      for (start = ptr; *ptr; ptr ++)
+      {
+       if (*ptr == quote)
+         *ptr = quote = '\0';
+       else if (quote)
+         continue;
+       else if (*ptr == '\\' && ptr[1])
+         _cups_strcpy(ptr, ptr + 1);
+       else if (*ptr == '\'' || *ptr == '\"')
+       {
+         quote = *ptr;
 
-      attr->values[i].string.text = _cupsStrAlloc(value);
+         if (ptr == start)
+           start ++;
+         else
+           _cups_strcpy(ptr, ptr + 1);
+       }
+       else if (*ptr == ',')
+       {
+         *ptr++ = '\0';
+         break;
+       }
+      }
 
-      if (ptr)
-        value = ptr;
+      attr->values[i].string.text = _cupsStrAlloc(start);
     }
   }
 }
@@ -2202,8 +2072,7 @@ cupsdSetPrinterAttr(
 void
 cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
 {
-  int          i,                      /* Looping var */
-               length;                 /* Length of browse attributes */
+  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 */
@@ -2211,7 +2080,6 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
   const char   *auth_supported;        /* Authentication supported */
   ipp_t                *oldattrs;              /* Old printer attributes */
   ipp_attribute_t *attr;               /* Attribute data */
-  cups_option_t        *option;                /* Current printer option */
   char         *name,                  /* Current user/group name */
                *filter;                /* Current filter */
   static const char * const air_none[] =
@@ -2254,8 +2122,7 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
     num_air = p->num_auth_info_required;
     air     = p->auth_info_required;
   }
-  else if ((p->type & CUPS_PRINTER_AUTHENTICATED) &&
-           (p->type & CUPS_PRINTER_DISCOVERED))
+  else if (p->type & CUPS_PRINTER_AUTHENTICATED)
   {
     num_air = 2;
     air     = air_userpass;
@@ -2276,7 +2143,7 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
 
 
     if ((auth_type = auth->type) == CUPSD_AUTH_DEFAULT)
-      auth_type = DefaultAuthType;
+      auth_type = cupsdDefaultAuthType();
 
     if (auth_type == CUPSD_AUTH_BASIC || auth_type == CUPSD_AUTH_BASICDIGEST)
       auth_supported = "basic";
@@ -2287,15 +2154,12 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
       auth_supported = "negotiate";
 #endif /* HAVE_GSSAPI */
 
-    if (!(p->type & CUPS_PRINTER_DISCOVERED))
-    {
-      if (auth_type != CUPSD_AUTH_NONE)
-       p->type |= CUPS_PRINTER_AUTHENTICATED;
-      else
-       p->type &= ~CUPS_PRINTER_AUTHENTICATED;
-    }
+    if (auth_type != CUPSD_AUTH_NONE)
+      p->type |= CUPS_PRINTER_AUTHENTICATED;
+    else
+      p->type &= ~CUPS_PRINTER_AUTHENTICATED;
   }
-  else if (!(p->type & CUPS_PRINTER_DISCOVERED))
+  else
     p->type &= ~CUPS_PRINTER_AUTHENTICATED;
 
  /*
@@ -2315,6 +2179,8 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
                NULL, p->location ? p->location : "");
   ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info",
                NULL, p->info ? p->info : "");
+  ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uuid", NULL,
+              p->uuid);
 
   if (cupsArrayCount(p->users) > 0)
   {
@@ -2342,7 +2208,7 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
   ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
                "auth-info-required", num_air, NULL, air);
 
-  if (cupsArrayCount(Banners) > 0 && !(p->type & CUPS_PRINTER_DISCOVERED))
+  if (cupsArrayCount(Banners) > 0)
   {
    /*
     * Setup the job-sheets-default attribute...
@@ -2363,126 +2229,117 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
   p->raw    = 0;
   p->remote = 0;
 
-  if (p->type & CUPS_PRINTER_DISCOVERED)
+ /*
+  * Assign additional attributes depending on whether this is a printer
+  * or class...
+  */
+
+  if (p->type & CUPS_PRINTER_CLASS)
   {
+    p->raw = 1;
+    p->type &= ~CUPS_PRINTER_OPTIONS;
+
    /*
-    * Tell the client this is a remote printer of some type...
+    * Add class-specific attributes...
     */
 
-    if (strchr(p->uri, '?'))
+    ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+                "printer-make-and-model", NULL, "Local Printer Class");
+    ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
+                "file:///dev/null");
+
+    if (p->num_printers > 0)
     {
      /*
-      * Strip trailing "?options" from URI...
+      * Add a list of member names; URIs are added in copy_printer_attrs...
       */
 
-      char *ptr;                       /* Pointer into URI */
+      attr    = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
+                             "member-names", p->num_printers, NULL, NULL);
+      p->type |= CUPS_PRINTER_OPTIONS;
 
-      strlcpy(resource, p->uri, sizeof(resource));
-      if ((ptr = strchr(resource, '?')) != NULL)
-        *ptr = '\0';
+      for (i = 0; i < p->num_printers; i ++)
+      {
+       if (attr != NULL)
+         attr->values[i].string.text = _cupsStrRetain(p->printers[i]->name);
 
-      ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
-                  "printer-uri-supported", NULL, resource);
+       p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
+      }
     }
-    else
-      ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
-                  "printer-uri-supported", NULL, p->uri);
+  }
+  else
+  {
+   /*
+    * Add printer-specific attributes...
+    */
 
-    ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info",
-                NULL, p->uri);
+    ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
+                p->sanitized_device_uri);
 
-    if (p->make_model)
-      ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
-                   "printer-make-and-model", NULL, p->make_model);
+   /*
+    * Assign additional attributes from the PPD file (if any)...
+    */
 
-    ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
-                p->uri);
+    load_ppd(p);
 
-    p->raw    = 1;
-    p->remote = 1;
-  }
-  else
-  {
    /*
-    * Assign additional attributes depending on whether this is a printer
-    * or class...
+    * Add filters for printer...
     */
 
-    if (p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
-    {
-      p->raw = 1;
-      p->type &= ~CUPS_PRINTER_OPTIONS;
+    cupsdSetPrinterReasons(p, "-cups-missing-filter-warning,"
+                             "cups-insecure-filter-warning");
 
-     /*
-      * Add class-specific attributes...
-      */
+    if (p->pc && p->pc->filters)
+    {
+      for (filter = (char *)cupsArrayFirst(p->pc->filters);
+          filter;
+          filter = (char *)cupsArrayNext(p->pc->filters))
+       add_printer_filter(p, p->filetype, filter);
+    }
+    else if (!(p->type & CUPS_PRINTER_REMOTE))
+    {
+      char     interface[1024];        /* Interface script */
 
-      if ((p->type & CUPS_PRINTER_IMPLICIT) && p->num_printers > 0 &&
-          p->printers[0]->make_model)
-       ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
-                     "printer-make-and-model", NULL, p->printers[0]->make_model);
-      else
-       ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
-                     "printer-make-and-model", NULL, "Local Printer Class");
 
-      ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
-                  "file:///dev/null");
+      snprintf(interface, sizeof(interface), "%s/interfaces/%s", ServerRoot,
+              p->name);
+      if (!access(interface, X_OK))
+      {
+       /*
+       * Yes, we have a System V style interface script; use it!
+       */
 
-      if (p->num_printers > 0)
+       snprintf(interface, sizeof(interface), "*/* 0 %s/interfaces/%s",
+                ServerRoot, p->name);
+       add_printer_filter(p, p->filetype, interface);
+      }
+      else
       {
        /*
-       * Add a list of member names; URIs are added in copy_printer_attrs...
+       * Add a filter from application/vnd.cups-raw to printer/name to
+       * handle "raw" printing by users.
        */
 
-       attr    = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
-                                "member-names", p->num_printers, NULL, NULL);
-        p->type |= CUPS_PRINTER_OPTIONS;
+       add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -");
 
-       for (i = 0; i < p->num_printers; i ++)
-       {
-          if (attr != NULL)
-            attr->values[i].string.text = _cupsStrRetain(p->printers[i]->name);
+       /*
+       * Add a PostScript filter, since this is still possibly PS printer.
+       */
 
-         p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
-        }
+       add_printer_filter(p, p->filetype,
+                          "application/vnd.cups-postscript 0 -");
       }
     }
-    else
-    {
-     /*
-      * Add printer-specific attributes...
-      */
-
-      ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
-                  p->sanitized_device_uri);
 
-     /*
-      * Assign additional attributes from the PPD file (if any)...
-      */
-
-      load_ppd(p);
-
-     /*
-      * Add filters for printer...
-      */
-
-      cupsdSetPrinterReasons(p, "-cups-missing-filter-warning,"
-                                "cups-insecure-filter-warning");
+    if (p->pc && p->pc->prefilters)
+    {
+      if (!p->prefiltertype)
+       p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name);
 
-      for (filter = (char *)cupsArrayFirst(p->filters);
+      for (filter = (char *)cupsArrayFirst(p->pc->prefilters);
           filter;
-          filter = (char *)cupsArrayNext(p->filters))
-       add_printer_filter(p, p->filetype, filter);
-
-      if (p->pre_filters)
-      {
-        p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name);
-
-        for (filter = (char *)cupsArrayFirst(p->pre_filters);
-            filter;
-            filter = (char *)cupsArrayNext(p->pre_filters))
-         add_printer_filter(p, p->prefiltertype, filter);
-      }
+          filter = (char *)cupsArrayNext(p->pc->prefilters))
+       add_printer_filter(p, p->prefiltertype, filter);
     }
   }
 
@@ -2582,98 +2439,8 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
   * Force sharing off for remote queues...
   */
 
-  if (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT))
+  if (p->type & CUPS_PRINTER_REMOTE)
     p->shared = 0;
-  else
-  {
-   /*
-    * Copy the printer options into a browse attributes string we can re-use.
-    */
-
-    const char *valptr;                /* Pointer into value */
-    char       *attrptr;               /* Pointer into attribute string */
-
-
-   /*
-    * Free the old browse attributes as needed...
-    */
-
-    if (p->browse_attrs)
-      free(p->browse_attrs);
-
-   /*
-    * Compute the length of all attributes + job-sheets, lease-duration,
-    * and BrowseLocalOptions.
-    */
-
-    for (length = 1, i = p->num_options, option = p->options;
-         i > 0;
-        i --, option ++)
-    {
-      length += strlen(option->name) + 2;
-
-      if (option->value)
-      {
-        for (valptr = option->value; *valptr; valptr ++)
-         if (strchr(" \"\'\\", *valptr))
-           length += 2;
-         else
-           length ++;
-      }
-    }
-
-    length += 13 + strlen(p->job_sheets[0]) + strlen(p->job_sheets[1]);
-    length += 32;
-    if (BrowseLocalOptions)
-      length += 12 + strlen(BrowseLocalOptions);
-
-   /*
-    * Allocate the new string...
-    */
-
-    if ((p->browse_attrs = calloc(1, length)) == NULL)
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "Unable to allocate %d bytes for browse data!",
-                     length);
-    else
-    {
-     /*
-      * Got the allocated string, now copy the options and attributes over...
-      */
-
-      sprintf(p->browse_attrs, "job-sheets=%s,%s lease-duration=%d",
-              p->job_sheets[0], p->job_sheets[1], BrowseTimeout);
-      attrptr = p->browse_attrs + strlen(p->browse_attrs);
-
-      if (BrowseLocalOptions)
-      {
-        sprintf(attrptr, " ipp-options=%s", BrowseLocalOptions);
-        attrptr += strlen(attrptr);
-      }
-
-      for (i = p->num_options, option = p->options;
-           i > 0;
-          i --, option ++)
-      {
-        *attrptr++ = ' ';
-       strcpy(attrptr, option->name);
-       attrptr += strlen(attrptr);
-
-       if (option->value)
-       {
-         *attrptr++ = '=';
-
-          for (valptr = option->value; *valptr; valptr ++)
-         {
-           if (strchr(" \"\'\\", *valptr))
-             *attrptr++ = '\\';
-
-           *attrptr++ = *valptr;
-         }
-       }
-      }
-    }
-  }
 
  /*
   * Populate the document-format-supported attribute...
@@ -2817,6 +2584,10 @@ 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,
@@ -2852,6 +2623,7 @@ cupsdSetPrinterState(
     ipp_pstate_t    s,                 /* I - New state */
     int             update)            /* I - Update printers.conf? */
 {
+  cupsd_job_t  *job;                   /* Current job */
   ipp_pstate_t old_state;              /* Old printer state */
   static const char * const printer_states[] =
   {                                    /* State strings */
@@ -2861,13 +2633,6 @@ cupsdSetPrinterState(
   };
 
 
- /*
-  * Can't set status of remote printers...
-  */
-
-  if (p->type & CUPS_PRINTER_DISCOVERED)
-    return;
-
  /*
   * Set the new state...
   */
@@ -2887,9 +2652,7 @@ cupsdSetPrinterState(
     * Let the browse code know this needs to be updated...
     */
 
-    BrowseNext     = p;
-    p->state_time  = time(NULL);
-    p->browse_time = 0;
+    p->state_time = time(NULL);
 
 #ifdef __sgi
     write_irix_state(p);
@@ -2905,6 +2668,17 @@ cupsdSetPrinterState(
   else
     cupsdSetPrinterReasons(p, "-paused");
 
+  if (old_state != s)
+  {
+    for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
+        job;
+        job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
+      if (job->reasons && job->state_value == IPP_JOB_PENDING &&
+         !_cups_strcasecmp(job->dest, p->name))
+       ippSetString(job->attrs, &job->reasons, 0,
+                    s == IPP_PRINTER_STOPPED ? "printer-stopped" : "none");
+  }
+
  /*
   * Clear the message for the queue when going to processing...
   */
@@ -2912,12 +2686,6 @@ cupsdSetPrinterState(
   if (s == IPP_PRINTER_PROCESSING)
     p->state_message[0] = '\0';
 
- /*
-  * Update the printer history...
-  */
-
-  cupsdAddPrinterHistory(p);
-
  /*
   * Let the browse protocols reflect the change...
   */
@@ -3093,22 +2861,6 @@ cupsdUpdatePrinters(void)
        p;
        p = (cupsd_printer_t *)cupsArrayNext(Printers))
   {
-   /*
-    * Remove remote printers if we are no longer browsing...
-    */
-
-    if (!Browsing &&
-        (p->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_DISCOVERED)))
-    {
-      if (p->type & CUPS_PRINTER_IMPLICIT)
-        cupsArrayRemove(ImplicitPrinters, p);
-
-      cupsArraySave(Printers);
-      cupsdDeletePrinter(p, 0);
-      cupsArrayRestore(Printers);
-      continue;
-    }
-
    /*
     * Update the operation policy pointer...
     */
@@ -3117,11 +2869,10 @@ cupsdUpdatePrinters(void)
       p->op_policy_ptr = DefaultPolicyPtr;
 
    /*
-    * Update printer attributes as needed...
+    * Update printer attributes...
     */
 
-    if (!(p->type & CUPS_PRINTER_DISCOVERED))
-      cupsdSetPrinterAttrs(p);
+    cupsdSetPrinterAttrs(p);
   }
 }
 
@@ -3214,8 +2965,7 @@ cupsdValidateDest(
       *printer = p;
 
     if (dtype)
-      *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
-                          CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED);
+      *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE);
 
     return (p->name);
   }
@@ -3224,12 +2974,12 @@ cupsdValidateDest(
   * Change localhost to the server name...
   */
 
-  if (!strcasecmp(hostname, "localhost"))
+  if (!_cups_strcasecmp(hostname, "localhost"))
     strlcpy(hostname, ServerName, sizeof(hostname));
 
   strlcpy(localname, hostname, sizeof(localname));
 
-  if (!strcasecmp(hostname, ServerName))
+  if (!_cups_strcasecmp(hostname, ServerName))
   {
    /*
     * Localize the hostname...
@@ -3246,7 +2996,7 @@ cupsdValidateDest(
 
       while (lptr != NULL)
       {
-       if (!strcasecmp(lptr, sptr))
+       if (!_cups_strcasecmp(lptr, sptr))
        {
           *lptr = '\0';
          break;
@@ -3266,15 +3016,14 @@ cupsdValidateDest(
   for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
        p;
        p = (cupsd_printer_t *)cupsArrayNext(Printers))
-    if (!strcasecmp(p->hostname, localname) &&
-        !strcasecmp(p->name, rptr))
+    if (!_cups_strcasecmp(p->hostname, localname) &&
+        !_cups_strcasecmp(p->name, rptr))
     {
       if (printer)
         *printer = p;
 
       if (dtype)
-       *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
-                            CUPS_PRINTER_REMOTE | CUPS_PRINTER_DISCOVERED);
+       *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE);
 
       return (p->name);
     }
@@ -3595,31 +3344,48 @@ add_printer_filter(
                                        /* Destination super/type */
                program[1024];          /* Program/filter name */
   int          cost;                   /* Cost of filter */
+  size_t       maxsize = 0;            /* Maximum supported file size */
   mime_type_t  *temptype,              /* MIME type looping var */
                *desttype;              /* Destination MIME type */
-  char         filename[1024],         /* Full filter filename */
-               *dirsep;                /* Pointer to directory separator */
-  struct stat  fileinfo;               /* File information */
+  mime_filter_t        *filterptr;             /* MIME filter */
+  char         filename[1024];         /* Full filter filename */
 
 
+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                  "add_printer_filter(p=%p(%s), filtertype=%p(%s/%s), "
+                 "filter=\"%s\")", p, p->name, filtertype, filtertype->super,
+                 filtertype->type, filter);
+
  /*
   * Parse the filter string; it should be in one of the following formats:
   *
   *     source/type cost program
+  *     source/type cost maxsize(nnnn) program
   *     source/type dest/type cost program
+  *     source/type dest/type cost maxsize(nnnn) program
   */
 
   if (sscanf(filter, "%15[^/]/%255s%*[ \t]%15[^/]/%255s%d%*[ \t]%1023[^\n]",
              super, type, dsuper, dtype, &cost, program) == 6)
   {
-    snprintf(dest, sizeof(dest), "%s/%s", dsuper, dtype);
+    snprintf(dest, sizeof(dest), "%s/%s/%s", p->name, dsuper, dtype);
+
+    if ((desttype = mimeType(MimeDatabase, "printer", dest)) == NULL)
+    {
+      desttype = mimeAddType(MimeDatabase, "printer", dest);
+      if (!p->dest_types)
+        p->dest_types = cupsArrayNew(NULL, NULL);
+
+      cupsArrayAdd(p->dest_types, desttype);
+    }
+
   }
   else
   {
     if (sscanf(filter, "%15[^/]/%255s%d%*[ \t]%1023[^\n]", super, type, &cost,
                program) == 4)
     {
-      strlcpy(dest, p->name, sizeof(dest));
+      desttype = filtertype;
     }
     else
     {
@@ -3629,9 +3395,28 @@ add_printer_filter(
     }
   }
 
+  if (!strncmp(program, "maxsize(", 8))
+  {
+    char       *ptr;                   /* Pointer into maxsize(nnnn) program */
+
+    maxsize = strtoll(program + 8, &ptr, 10);
+
+    if (*ptr != ')')
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR, "%s: invalid filter string \"%s\"!",
+                      p->name, filter);
+      return;
+    }
+
+    ptr ++;
+    while (_cups_isspace(*ptr))
+      ptr ++;
+
+    _cups_strcpy(program, ptr);
+  }
+
  /*
-  * See if the filter program exists; if not, stop the printer and flag
-  * the error!
+  * Check permissions on the filter and its containing directory...
   */
 
   if (strcmp(program, "-"))
@@ -3641,86 +3426,20 @@ add_printer_filter(
     else
       snprintf(filename, sizeof(filename), "%s/filter/%s", ServerBin, program);
 
-    if (stat(filename, &fileinfo))
-    {
-      memset(&fileinfo, 0, sizeof(fileinfo));
-
-      snprintf(p->state_message, sizeof(p->state_message),
-               "Printer driver \"%s\" not available: %s", filename,
-              strerror(errno));
-      cupsdSetPrinterReasons(p, "+cups-missing-filter-warning");
-
-      cupsdLogMessage(CUPSD_LOG_ERROR, "%s: %s", p->name, p->state_message);
-    }
-
-   /*
-    * When running as root, do additional security checks...
-    */
-
-    else if (!RunUser)
-    {
-     /*
-      * Only use filters that are owned by root and do not have world write
-      * permissions.
-      */
-
-      if (fileinfo.st_uid ||
-          (fileinfo.st_mode & (S_ISUID | S_IWGRP | S_IWOTH)) != 0)
-      {
-       snprintf(p->state_message, sizeof(p->state_message),
-                "Printer driver \"%s\" has insecure permissions (%d/0%o).",
-                filename, (int)fileinfo.st_uid, fileinfo.st_mode);
-
-       cupsdSetPrinterReasons(p, "+cups-insecure-filter-warning");
-
-       cupsdLogMessage(CUPSD_LOG_WARN, "%s: %s", p->name, p->state_message);
-      }
-      else if (fileinfo.st_mode)
-      {
-       /*
-       * Similarly, check that the parent directory is also owned by root and
-       * does not have world write permissions.
-       */
-
-       if ((dirsep = strrchr(filename, '/')) != NULL)
-         *dirsep = '\0';
-
-       if (!stat(filename, &fileinfo) &&
-           (fileinfo.st_uid ||
-            (fileinfo.st_mode & (S_ISUID | S_IWOTH)) != 0))
-       {
-         snprintf(p->state_message, sizeof(p->state_message),
-                  "Printer driver directory \"%s\" has insecure permissions "
-                  "(%d/0%o).", filename, (int)fileinfo.st_uid,
-                  fileinfo.st_mode);
-
-         cupsdSetPrinterReasons(p, "+cups-insecure-filter-warning");
-
-         cupsdLogMessage(CUPSD_LOG_WARN, "%s: %s", p->name, p->state_message);
-       }
-      }
-    }
+    _cupsFileCheck(filename, _CUPS_FILE_CHECK_PROGRAM, !RunUser,
+                   cupsdLogFCMessage, p);
   }
 
  /*
   * Add the filter to the MIME database, supporting wildcards as needed...
   */
 
-  if ((desttype = mimeType(MimeDatabase, "printer", dest)) == NULL)
-  {
-    desttype = mimeAddType(MimeDatabase, "printer", dest);
-    if (!p->dest_types)
-      p->dest_types = cupsArrayNew(NULL, NULL);
-
-    cupsArrayAdd(p->dest_types, desttype);
-  }
-
   for (temptype = mimeFirstType(MimeDatabase);
        temptype;
        temptype = mimeNextType(MimeDatabase))
-    if (((super[0] == '*' && strcasecmp(temptype->super, "printer")) ||
-         !strcasecmp(temptype->super, super)) &&
-        (type[0] == '*' || !strcasecmp(temptype->type, type)))
+    if (((super[0] == '*' && _cups_strcasecmp(temptype->super, "printer")) ||
+         !_cups_strcasecmp(temptype->super, super)) &&
+        (type[0] == '*' || !_cups_strcasecmp(temptype->type, type)))
     {
       if (desttype != filtertype)
       {
@@ -3729,7 +3448,8 @@ add_printer_filter(
                        "%s", p->name, temptype->super, temptype->type,
                        desttype->super, desttype->type,
                        cost, program);
-        mimeAddFilter(MimeDatabase, temptype, desttype, cost, program);
+        filterptr = mimeAddFilter(MimeDatabase, temptype, desttype, cost,
+                                 program);
 
         if (!mimeFilterLookup(MimeDatabase, desttype, filtertype))
         {
@@ -3737,7 +3457,7 @@ add_printer_filter(
                          "add_printer_filter: %s: adding filter %s/%s %s/%s "
                          "0 -", p->name, desttype->super, desttype->type,
                          filtertype->super, filtertype->type);
-          mimeAddFilter(MimeDatabase, desttype, filtertype, cost, "-");
+          mimeAddFilter(MimeDatabase, desttype, filtertype, 0, "-");
         }
       }
       else
@@ -3747,8 +3467,12 @@ add_printer_filter(
                        "%s", p->name, temptype->super, temptype->type,
                        filtertype->super, filtertype->type,
                        cost, program);
-        mimeAddFilter(MimeDatabase, temptype, filtertype, cost, program);
+        filterptr = mimeAddFilter(MimeDatabase, temptype, filtertype, cost,
+                                 program);
       }
+
+      if (filterptr)
+       filterptr->maxsize = maxsize;
     }
 }
 
@@ -3798,7 +3522,7 @@ add_printer_formats(cupsd_printer_t *p)   /* I - Printer */
        type;
        type = mimeNextType(MimeDatabase))
   {
-    if (!strcasecmp(type->super, "printer"))
+    if (!_cups_strcasecmp(type->super, "printer"))
       continue;
 
     snprintf(mimetype, sizeof(mimetype), "%s/%s", type->super, type->type);
@@ -3848,7 +3572,7 @@ add_printer_formats(cupsd_printer_t *p)   /* I - Printer */
     attr->values[i].string.text = _cupsStrAlloc(mimetype);
   }
 
-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
   {
     char               pdl[1024];      /* Buffer to build pdl list */
     mime_filter_t      *filter;        /* MIME filter looping var */
@@ -3881,20 +3605,20 @@ add_printer_formats(cupsd_printer_t *p) /* I - Printer */
         type;
         type = (mime_type_t *)cupsArrayNext(p->filetypes))
     {
-      if (!strcasecmp(type->super, "application"))
+      if (!_cups_strcasecmp(type->super, "application"))
       {
-        if (!strcasecmp(type->type, "pdf"))
+        if (!_cups_strcasecmp(type->type, "pdf"))
          strlcat(pdl, "application/pdf,", sizeof(pdl));
-        else if (!strcasecmp(type->type, "postscript"))
+        else if (!_cups_strcasecmp(type->type, "postscript"))
          strlcat(pdl, "application/postscript,", sizeof(pdl));
       }
-      else if (!strcasecmp(type->super, "image"))
+      else if (!_cups_strcasecmp(type->super, "image"))
       {
-        if (!strcasecmp(type->type, "jpeg"))
+        if (!_cups_strcasecmp(type->type, "jpeg"))
          strlcat(pdl, "image/jpeg,", sizeof(pdl));
-       else if (!strcasecmp(type->type, "png"))
+       else if (!_cups_strcasecmp(type->type, "png"))
          strlcat(pdl, "image/png,", sizeof(pdl));
-       else if (!strcasecmp(type->type, "pwg-raster"))
+       else if (!_cups_strcasecmp(type->type, "pwg-raster"))
          strlcat(pdl, "image/pwg-raster,", sizeof(pdl));
       }
     }
@@ -3904,22 +3628,7 @@ add_printer_formats(cupsd_printer_t *p)  /* I - Printer */
 
     cupsdSetString(&p->pdl, pdl);
   }
-#endif /* HAVE_DNSSD */
-}
-
-
-/*
- * 'add_string_array()' - Add a string to an array of CUPS strings.
- */
-
-static void
-add_string_array(cups_array_t **a,     /* I - Array */
-                const char   *s)       /* I - String */
-{
-  if (!*a)
-    *a = cupsArrayNew(NULL, NULL);
-
-  cupsArrayAdd(*a, _cupsStrAlloc(s));
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
 }
 
 
@@ -3932,7 +3641,9 @@ compare_printers(void *first,             /* I - First printer */
                  void *second,         /* I - Second printer */
                 void *data)            /* I - App data (not used) */
 {
-  return (strcasecmp(((cupsd_printer_t *)first)->name,
+  (void)data;
+
+  return (_cups_strcasecmp(((cupsd_printer_t *)first)->name,
                      ((cupsd_printer_t *)second)->name));
 }
 
@@ -3987,26 +3698,6 @@ delete_printer_filters(
 }
 
 
-/*
- * 'delete_string_array()' - Delete an array of CUPS strings.
- */
-
-static void
-delete_string_array(cups_array_t **a)  /* I - Array */
-{
-  char *ptr;                           /* Current string */
-
-
-  for (ptr = (char *)cupsArrayFirst(*a);
-       ptr;
-       ptr = (char *)cupsArrayNext(*a))
-    _cupsStrFree(ptr);
-
-  cupsArrayDelete(*a);
-  *a = NULL;
-}
-
-
 /*
  * 'dirty_printer()' - Mark config and state files dirty for the specified
  *                     printer.
@@ -4015,9 +3706,7 @@ delete_string_array(cups_array_t **a)     /* I - Array */
 static void
 dirty_printer(cupsd_printer_t *p)      /* I - Printer */
 {
-  if (p->type & CUPS_PRINTER_DISCOVERED)
-    cupsdMarkDirty(CUPSD_DIRTY_REMOTE);
-  else if (p->type & CUPS_PRINTER_CLASS)
+  if (p->type & CUPS_PRINTER_CLASS)
     cupsdMarkDirty(CUPSD_DIRTY_CLASSES);
   else
     cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
@@ -4035,11 +3724,8 @@ static void
 load_ppd(cupsd_printer_t *p)           /* I - Printer */
 {
   int          i, j, k;                /* Looping vars */
-  cups_file_t  *cache;                 /* IPP cache file */
-  char         cache_name[1024];       /* IPP cache filename */
-  struct stat  cache_info;             /* IPP cache file info */
-  char         pwg_name[1024];         /* PWG cache filename */
-  struct stat  pwg_info;               /* PWG cache file info */
+  char         cache_name[1024];       /* Cache filename */
+  struct stat  cache_info;             /* Cache file info */
   ppd_file_t   *ppd;                   /* PPD file */
   char         ppd_name[1024];         /* PPD filename */
   struct stat  ppd_info;               /* PPD file info */
@@ -4060,13 +3746,14 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
   _pwg_map_t   *pwgsource,             /* Current PWG source */
                *pwgtype;               /* Current PWG type */
   ipp_attribute_t *attr;               /* Attribute data */
-  ipp_value_t  *val;                   /* Attribute value */
+  _ipp_value_t *val;                   /* Attribute value */
   int          num_finishings,         /* Number of finishings */
                finishings[5];          /* finishings-supported values */
   int          num_qualities,          /* Number of print-quality values */
                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 */
   static const char * const sides[3] = /* sides-supported values */
                {
                  "one-sided",
@@ -4085,44 +3772,33 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
   * Check to see if the cache is up-to-date...
   */
 
-  snprintf(cache_name, sizeof(cache_name), "%s/%s.ipp4", CacheDir, p->name);
+  snprintf(cache_name, sizeof(cache_name), "%s/%s.data", CacheDir, p->name);
   if (stat(cache_name, &cache_info))
     cache_info.st_mtime = 0;
 
-  snprintf(pwg_name, sizeof(pwg_name), "%s/%s.pwg3", CacheDir, p->name);
-  if (stat(pwg_name, &pwg_info))
-    pwg_info.st_mtime = 0;
-
   snprintf(ppd_name, sizeof(ppd_name), "%s/ppd/%s.ppd", ServerRoot, p->name);
   if (stat(ppd_name, &ppd_info))
     ppd_info.st_mtime = 1;
 
   ippDelete(p->ppd_attrs);
-  p->ppd_attrs = ippNew();
-
-  _pwgDestroy(p->pwg);
-  p->pwg = NULL;
+  p->ppd_attrs = NULL;
 
-  if (pwg_info.st_mtime >= ppd_info.st_mtime)
-    p->pwg = _pwgCreateWithFile(pwg_name);
+  _ppdCacheDestroy(p->pc);
+  p->pc = NULL;
 
-  if (cache_info.st_mtime >= ppd_info.st_mtime && p->pwg &&
-      (cache = cupsFileOpen(cache_name, "r")) != NULL)
+  if (cache_info.st_mtime >= ppd_info.st_mtime)
   {
-   /*
-    * Load cached information and return...
-    */
-
     cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", cache_name);
 
-    if (ippReadIO(cache, (ipp_iocb_t)cupsFileRead, 1, NULL,
-                  p->ppd_attrs) == IPP_DATA)
+    if ((p->pc = _ppdCacheCreateWithFile(cache_name, &p->ppd_attrs)) != NULL &&
+        p->ppd_attrs)
     {
-      cupsFileClose(cache);
+     /*
+      * Loaded successfully!
+      */
+
       return;
     }
-
-    cupsFileClose(cache);
   }
 
  /*
@@ -4131,27 +3807,23 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
 
   cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
 
-  _pwgDestroy(p->pwg);
-  p->pwg = NULL;
-
   cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", ppd_name);
 
-  delete_string_array(&(p->filters));
-  delete_string_array(&(p->pre_filters));
-
   p->type &= ~CUPS_PRINTER_OPTIONS;
   p->type |= CUPS_PRINTER_BW;
 
   finishings[0]  = IPP_FINISHINGS_NONE;
   num_finishings = 1;
 
-  if ((ppd = ppdOpenFile(ppd_name)) != NULL)
+  p->ppd_attrs = ippNew();
+
+  if ((ppd = _ppdOpenFile(ppd_name, _PPD_LOCALIZATION_NONE)) != NULL)
   {
    /*
     * Add make/model and other various attributes...
     */
 
-    p->pwg = _pwgCreateWithPPD(ppd);
+    p->pc = _ppdCacheCreateWithPPD(ppd);
 
     ppdMarkDefaults(ppd);
 
@@ -4162,7 +3834,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
     if (!ppd->manual_copies)
       p->type |= CUPS_PRINTER_COPIES;
     if ((ppd_attr = ppdFindAttr(ppd, "cupsFax", NULL)) != NULL)
-      if (ppd_attr->value && !strcasecmp(ppd_attr->value, "true"))
+      if (ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true"))
        p->type |= CUPS_PRINTER_FAX;
 
     ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, "color-supported",
@@ -4195,9 +3867,9 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
       if (ppdFindChoice(output_mode, "draft") ||
           ppdFindChoice(output_mode, "fast"))
         qualities[num_qualities ++] = IPP_QUALITY_DRAFT;
-      if (ppdFindChoice(output_mode, "normal") ||
-          ppdFindChoice(output_mode, "good"))
-        qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
+
+      qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
+
       if (ppdFindChoice(output_mode, "best") ||
           ppdFindChoice(output_mode, "high"))
         qualities[num_qualities ++] = IPP_QUALITY_HIGH;
@@ -4219,8 +3891,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
       qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
       qualities[num_qualities ++] = IPP_QUALITY_HIGH;
     }
-
-    if (num_qualities == 0)
+    else
       qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
 
     ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
@@ -4255,7 +3926,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
     * Add media options from the PPD file...
     */
 
-    if (ppd->num_sizes == 0 || !p->pwg)
+    if (ppd->num_sizes == 0 || !p->pc)
     {
       if (!ppdFindAttr(ppd, "APScannerOnly", NULL))
        cupsdLogMessage(CUPSD_LOG_CRIT,
@@ -4274,7 +3945,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
       */
 
       if ((size = ppdPageSize(ppd, NULL)) != NULL)
-        pwgsize = _pwgGetSize(p->pwg, size->name);
+        pwgsize = _ppdCacheGetSize(p->pc, size->name);
       else
         pwgsize = NULL;
 
@@ -4294,12 +3965,12 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
        media_type = ppdFindMarkedChoice(ppd, "MediaType");
        col        = new_media_col(pwgsize,
                                   input_slot ?
-                                      _pwgGetSource(p->pwg,
-                                                    input_slot->choice) :
+                                      _ppdCacheGetSource(p->pc,
+                                                         input_slot->choice) :
                                       NULL,
                                   media_type ?
-                                      _pwgGetType(p->pwg,
-                                                  media_type->choice) :
+                                      _ppdCacheGetType(p->pc,
+                                                       media_type->choice) :
                                       NULL);
 
        ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-default",
@@ -4311,8 +3982,8 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
       * media-supported
       */
 
-      num_media = p->pwg->num_sizes;
-      if (p->pwg->custom_min_keyword)
+      num_media = p->pc->num_sizes;
+      if (p->pc->custom_min_keyword)
        num_media += 2;
 
       if ((attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
@@ -4321,16 +3992,16 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
       {
        val = attr->values;
 
-        for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes;
+        for (i = p->pc->num_sizes, pwgsize = p->pc->sizes;
             i > 0;
             i --, pwgsize ++, val ++)
          val->string.text = _cupsStrRetain(pwgsize->map.pwg);
 
-        if (p->pwg->custom_min_keyword)
+        if (p->pc->custom_min_keyword)
        {
-         val->string.text = _cupsStrRetain(p->pwg->custom_min_keyword);
+         val->string.text = _cupsStrRetain(p->pc->custom_min_keyword);
          val ++;
-         val->string.text = _cupsStrRetain(p->pwg->custom_max_keyword);
+         val->string.text = _cupsStrRetain(p->pc->custom_max_keyword);
         }
       }
 
@@ -4338,12 +4009,12 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
       * media-source-supported
       */
 
-      if (p->pwg->num_sources > 0 &&
+      if (p->pc->num_sources > 0 &&
           (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                               "media-source-supported", p->pwg->num_sources,
+                               "media-source-supported", p->pc->num_sources,
                                NULL, NULL)) != NULL)
       {
-       for (i = p->pwg->num_sources, pwgsource = p->pwg->sources,
+       for (i = p->pc->num_sources, pwgsource = p->pc->sources,
                 val = attr->values;
             i > 0;
             i --, pwgsource ++, val ++)
@@ -4354,12 +4025,12 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
       * media-type-supported
       */
 
-      if (p->pwg->num_types > 0 &&
+      if (p->pc->num_types > 0 &&
           (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                               "media-type-supported", p->pwg->num_types,
+                               "media-type-supported", p->pc->num_types,
                                NULL, NULL)) != NULL)
       {
-       for (i = p->pwg->num_types, pwgtype = p->pwg->types,
+       for (i = p->pc->num_types, pwgtype = p->pc->types,
                 val = attr->values;
             i > 0;
             i --, pwgtype ++, val ++)
@@ -4370,7 +4041,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
       * media-*-margin-supported
       */
 
-      for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes, num_margins = 0;
+      for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
           i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
           i --, pwgsize ++)
       {
@@ -4392,7 +4063,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
         ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
                      "media-bottom-margin-supported", 0);
 
-      for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes, num_margins = 0;
+      for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
           i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
           i --, pwgsize ++)
       {
@@ -4414,7 +4085,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
         ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
                      "media-left-margin-supported", 0);
 
-      for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes, num_margins = 0;
+      for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
           i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
           i --, pwgsize ++)
       {
@@ -4436,7 +4107,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
         ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
                      "media-right-margin-supported", 0);
 
-      for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes, num_margins = 0;
+      for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, num_margins = 0;
           i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
           i --, pwgsize ++)
       {
@@ -4462,23 +4133,23 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
       * media-col-database
       */
 
-      num_media = p->pwg->num_sizes;
-      if (p->pwg->num_sources)
+      num_media = p->pc->num_sizes;
+      if (p->pc->num_sources)
       {
-        if (p->pwg->num_types > 0)
-         num_media += p->pwg->num_sizes * p->pwg->num_sources *
-                      p->pwg->num_types;
+        if (p->pc->num_types > 0)
+         num_media += p->pc->num_sizes * p->pc->num_sources *
+                      p->pc->num_types;
        else
-          num_media += p->pwg->num_sizes * p->pwg->num_sources;
+          num_media += p->pc->num_sizes * p->pc->num_sources;
       }
-      else if (p->pwg->num_types)
-        num_media += p->pwg->num_sizes * p->pwg->num_types;
+      else if (p->pc->num_types)
+        num_media += p->pc->num_sizes * p->pc->num_types;
 
       if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER,
                                     "media-col-database", num_media,
                                    NULL)) != NULL)
       {
-        for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes, val = attr->values;
+        for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, val = attr->values;
             i > 0;
             i --, pwgsize ++)
        {
@@ -4496,17 +4167,17 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
          * type...
          */
 
-         if (p->pwg->num_sources > 0)
+         if (p->pc->num_sources > 0)
          {
-           for (j = p->pwg->num_sources, pwgsource = p->pwg->sources;
+           for (j = p->pc->num_sources, pwgsource = p->pc->sources;
                 j > 0;
                 j --, pwgsource ++)
            {
              ppdMarkOption(ppd, "InputSlot", pwgsource->ppd);
 
-             if (p->pwg->num_types > 0)
+             if (p->pc->num_types > 0)
              {
-               for (k = p->pwg->num_types, pwgtype = p->pwg->types;
+               for (k = p->pc->num_types, pwgtype = p->pc->types;
                     k > 0;
                     k --, pwgtype ++)
                {
@@ -4525,9 +4196,9 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
              }
            }
          }
-         else if (p->pwg->num_types > 0)
+         else if (p->pc->num_types > 0)
          {
-           for (j = p->pwg->num_types, pwgtype = p->pwg->types;
+           for (j = p->pc->num_types, pwgtype = p->pc->types;
                 j > 0;
                 j --, pwgtype ++)
            {
@@ -4552,42 +4223,42 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
     * Output bin...
     */
 
-    if (p->pwg && p->pwg->num_bins > 0)
+    if (p->pc && p->pc->num_bins > 0)
     {
       attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                          "output-bin-supported", p->pwg->num_bins,
+                          "output-bin-supported", p->pc->num_bins,
                           NULL, NULL);
 
       if (attr != NULL)
       {
        for (i = 0, val = attr->values;
-            i < p->pwg->num_bins;
+            i < p->pc->num_bins;
             i ++, val ++)
-         val->string.text = _cupsStrAlloc(p->pwg->bins[i].pwg);
+         val->string.text = _cupsStrAlloc(p->pc->bins[i].pwg);
       }
 
       if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
       {
-       for (i = 0; i < p->pwg->num_bins; i ++)
-         if (!strcmp(p->pwg->bins[i].ppd, output_bin->defchoice))
+       for (i = 0; i < p->pc->num_bins; i ++)
+         if (!strcmp(p->pc->bins[i].ppd, output_bin->defchoice))
            break;
 
-        if (i >= p->pwg->num_bins)
+        if (i >= p->pc->num_bins)
          i = 0;
 
        ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                    "output-bin-default", NULL, p->pwg->bins[i].pwg);
+                    "output-bin-default", NULL, p->pc->bins[i].pwg);
       }
       else
         ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                    "output-bin-default", NULL, p->pwg->bins[0].pwg);
+                    "output-bin-default", NULL, p->pc->bins[0].pwg);
     }
     else if (((ppd_attr = ppdFindAttr(ppd, "DefaultOutputOrder",
                                      NULL)) != NULL &&
-             !strcasecmp(ppd_attr->value, "Reverse")) ||
+             !_cups_strcasecmp(ppd_attr->value, "Reverse")) ||
             (!ppd_attr && ppd->manufacturer && /* "Compatibility heuristic" */
-             (!strcasecmp(ppd->manufacturer, "epson") ||
-              !strcasecmp(ppd->manufacturer, "lexmark"))))
+             (!_cups_strcasecmp(ppd->manufacturer, "epson") ||
+              !_cups_strcasecmp(ppd->manufacturer, "lexmark"))))
     {
      /*
       * Report that this printer has a single output bin that leaves pages face
@@ -4608,7 +4279,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
     }
 
    /*
-    * output-mode...
+    * output-mode and print-color-mode...
     */
 
     if (ppd->color_device)
@@ -4623,6 +4294,11 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
                     "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);
+      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                   "print-color-mode-default", NULL, "color");
     }
     else
     {
@@ -4630,6 +4306,11 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
                    "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");
     }
 
    /*
@@ -4743,10 +4424,10 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
       ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
                    "sides-supported", 3, NULL, sides);
 
-      if (!strcasecmp(duplex->defchoice, "DuplexTumble"))
+      if (!_cups_strcasecmp(duplex->defchoice, "DuplexTumble"))
        ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
                     "sides-default", NULL, "two-sided-short-edge");
-      else if (!strcasecmp(duplex->defchoice, "DuplexNoTumble"))
+      else if (!_cups_strcasecmp(duplex->defchoice, "DuplexNoTumble"))
        ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
                     "sides-default", NULL, "two-sided-long-edge");
       else
@@ -4785,116 +4466,31 @@ load_ppd(cupsd_printer_t *p)           /* I - Printer */
        p->type |= CUPS_PRINTER_SMALL;
 
     if ((ppd_attr = ppdFindAttr(ppd, "APICADriver", NULL)) != NULL &&
-        ppd_attr->value && !strcasecmp(ppd_attr->value, "true"))
+        ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true"))
     {
       if ((ppd_attr = ppdFindAttr(ppd, "APScannerOnly", NULL)) != NULL &&
-         ppd_attr->value && !strcasecmp(ppd_attr->value, "true"))
+         ppd_attr->value && !_cups_strcasecmp(ppd_attr->value, "true"))
         p->type |= CUPS_PRINTER_SCANNER;
       else
         p->type |= CUPS_PRINTER_MFP;
     }
 
    /*
-    * Add a filter from application/vnd.cups-raw to printer/name to
-    * handle "raw" printing by users.
-    */
-
-    add_string_array(&(p->filters), "application/vnd.cups-raw 0 -");
-
-   /*
-    * Add any pre-filters in the PPD file...
-    */
-
-    if ((ppd_attr = ppdFindAttr(ppd, "cupsPreFilter", NULL)) != NULL)
-    {
-      for (; ppd_attr; ppd_attr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL))
-       if (ppd_attr->value)
-         add_string_array(&(p->pre_filters), ppd_attr->value);
-    }
-
-   /*
-    * Add any filters in the PPD file...
+    * Scan the filters in the PPD file...
     */
 
-    if ((ppd_attr = ppdFindAttr(ppd, "cupsFilter2", NULL)) != NULL)
+    if (p->pc)
     {
-     /*
-      * Use new cupsFilter2 filter syntax...
-      */
-
-      for (; ppd_attr; ppd_attr = ppdFindNextAttr(ppd, "cupsFilter2", NULL))
-      {
-        add_string_array(&(p->filters), ppd_attr->value);
-
-        if (!strncasecmp(ppd_attr->value, "application/vnd.cups-command", 28) &&
-            isspace(ppd_attr->value[28] & 255))
-          p->type |= CUPS_PRINTER_COMMANDS;
-      }
-    }
-    else
-    {
-     /*
-      * Use old cupsFilter syntax...
-      */
-
-      DEBUG_printf(("ppd->num_filters = %d\n", ppd->num_filters));
-      for (i = 0; i < ppd->num_filters; i ++)
+      for (filter = (const char *)cupsArrayFirst(p->pc->filters);
+          filter;
+          filter = (const char *)cupsArrayNext(p->pc->filters))
       {
-        DEBUG_printf(("ppd->filters[%d] = \"%s\"\n", i, ppd->filters[i]));
-        add_string_array(&(p->filters), ppd->filters[i]);
-
-        if (!strncasecmp(ppd->filters[i], "application/vnd.cups-command", 28) &&
-            isspace(ppd->filters[i][28] & 255))
-          p->type |= CUPS_PRINTER_COMMANDS;
-      }
-    }
-
-    if ((ppd_attr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL &&
-       ppd_attr->value &&
-       (!ppd_attr->value[0] || !strcasecmp(ppd_attr->value, "none")))
-    {
-     /*
-      * Printer does not support CUPS command files (or any commands as far as
-      * CUPS is concerned...
-      */
-
-      p->type &= ~CUPS_PRINTER_COMMANDS;
-    }
-    else if (ppd->num_filters == 0)
-    {
-     /*
-      * If there are no filters, add PostScript printing filters.
-      */
-
-      add_string_array(&(p->filters),
-                       "application/vnd.cups-command 0 commandtops");
-      add_string_array(&(p->filters),
-                       "application/vnd.cups-postscript 0 -");
-
-      p->type |= CUPS_PRINTER_COMMANDS;
-    }
-    else if (!(p->type & CUPS_PRINTER_COMMANDS))
-    {
-     /*
-      * See if this is a PostScript device without a command filter...
-      */
-
-      for (i = 0; i < ppd->num_filters; i ++)
-       if (!strncasecmp(ppd->filters[i],
-                        "application/vnd.cups-postscript", 31) &&
-            isspace(ppd->filters[i][31] & 255))
+       if (!_cups_strncasecmp(filter, "application/vnd.cups-command", 28) &&
+           _cups_isspace(filter[28]))
+       {
+         p->type |= CUPS_PRINTER_COMMANDS;
          break;
-
-      if (i < ppd->num_filters)
-      {
-       /*
-       * Add the generic PostScript command filter...
-       */
-
-       add_string_array(&(p->filters),
-                        "application/vnd.cups-command application/postscript "
-                        "0 commandtops");
-       p->type |= CUPS_PRINTER_COMMANDS;
+       }
       }
     }
 
@@ -4905,12 +4501,11 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
                *end;                   /* End of name */
       int      count;                  /* Number of commands */
 
-
-      if (ppd_attr && ppd_attr->value && ppd_attr->value[0])
+      if ((ppd_attr = ppdFindAttr(ppd, "cupsCommands", NULL)) != NULL)
       {
        for (count = 0, start = ppd_attr->value; *start; count ++)
        {
-         while (isspace(*start & 255))
+         while (_cups_isspace(*start))
            start ++;
 
          if (!*start)
@@ -5017,10 +4612,6 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
        attr->values[i].string.text = _cupsStrAlloc("bcp");
     }
 
-#ifdef HAVE_DNSSD
-    cupsdSetString(&p->product, ppd->product);
-#endif /* HAVE_DNSSD */
-
     if (ppdFindAttr(ppd, "APRemoteQueueID", NULL))
       p->type |= CUPS_PRINTER_REMOTE;
 
@@ -5031,7 +4622,9 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
     */
 
     if ((ppd_attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL &&
-        ppd_attr->value)
+        ppd_attr->value &&
+       !_cupsFileCheck(ppd_attr->value, _CUPS_FILE_CHECK_FILE, !RunUser,
+                       cupsdLogFCMessage, p))
     {
       CGImageRef       imageRef = NULL;/* Current icon image */
       CGImageRef       biggestIconRef = NULL;
@@ -5179,19 +4772,6 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
     cupsdLogMessage(CUPSD_LOG_INFO,
                    "Hint: Run \"cupstestppd %s\" and fix any errors.",
                    ppd_name);
-
-   /*
-    * Add a filter from application/vnd.cups-raw to printer/name to
-    * handle "raw" printing by users.
-    */
-
-    add_string_array(&(p->filters), "application/vnd.cups-raw 0 -");
-
-   /*
-    * Add a PostScript filter, since this is still possibly PS printer.
-    */
-
-    add_string_array(&(p->filters), "application/vnd.cups-postscript 0 -");
   }
   else
   {
@@ -5213,10 +4793,6 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
       ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
                   "printer-make-and-model", NULL,
                   "Local System V Printer");
-
-      snprintf(interface, sizeof(interface), "*/* 0 %s/interfaces/%s",
-              ServerRoot, p->name);
-      add_string_array(&(p->filters), interface);
     }
     else if (!strncmp(p->device_uri, "ipp://", 6) &&
             (strstr(p->device_uri, "/printers/") != NULL ||
@@ -5289,7 +4865,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
   ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
                "finishings-default", IPP_FINISHINGS_NONE);
 
-  if (ppd && (cache = cupsFileOpen(cache_name, "w9")) != NULL)
+  if (ppd && p->pc)
   {
    /*
     * Save cached PPD attributes to disk...
@@ -5297,20 +4873,7 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
 
     cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Saving %s...", cache_name);
 
-    p->ppd_attrs->state = IPP_IDLE;
-
-    if (ippWriteIO(cache, (ipp_iocb_t)cupsFileWrite, 1, NULL,
-                   p->ppd_attrs) != IPP_DATA)
-    {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "Unable to save PPD cache file \"%s\" - %s", cache_name,
-                     strerror(errno));
-      unlink(cache_name);
-    }
-
-    cupsFileClose(cache);
-
-    _pwgWriteFile(p->pwg, pwg_name);
+    _ppdCacheWriteFile(p->pc, cache_name, p->ppd_attrs);
   }
   else
   {
@@ -5320,10 +4883,82 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
 
     if (cache_info.st_mtime)
       unlink(cache_name);
+  }
+}
+
+
+/*
+ * 'log_ipp_conformance()' - Log an IPP conformance issue with a printer.
+ */
 
-    if (pwg_info.st_mtime)
-      unlink(pwg_name);
+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__ */
 }