]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/printers.c
Move debug printfs to internal usage only.
[thirdparty/cups.git] / scheduler / printers.c
index b187c2bffe78e90c3539fc65ba4eb93b5da5e090..f168b4c1a4b378ec3bb8255eee678d3a97b84637 100644 (file)
@@ -1,59 +1,11 @@
 /*
- * "$Id: printers.c 7968 2008-09-19 23:03:01Z mike $"
+ * Printer routines for the CUPS scheduler.
  *
- *   Printer routines for the CUPS scheduler.
+ * Copyright © 2007-2018 by Apple Inc.
+ * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
  *
- *   Copyright 2007-2011 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.
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more
+ * information.
  */
 
 /*
@@ -76,6 +28,9 @@
 #ifdef HAVE_SYS_VFS_H
 #  include <sys/vfs.h>
 #endif /* HAVE_SYS_VFS_H */
+#ifdef __APPLE__
+#  include <asl.h>
+#endif /* __APPLE__ */
 
 
 /*
@@ -90,12 +45,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 ipp_t   *new_media_col(_pwg_size_t *size, const char *source,
+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);
 
 
@@ -128,6 +79,8 @@ cupsdAddPrinter(const char *name)    /* I - Name of printer */
     return (NULL);
   }
 
+  _cupsRWInit(&p->lock);
+
   cupsdSetString(&p->name, name);
   cupsdSetString(&p->info, name);
   cupsdSetString(&p->hostname, ServerName);
@@ -135,15 +88,16 @@ 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;
-  p->state_time = time(NULL);
-  p->accepting  = 0;
-  p->shared     = DefaultShared;
-  p->filetype   = mimeAddType(MimeDatabase, "printer", name);
+  p->config_time = time(NULL);
+  p->state       = IPP_PRINTER_STOPPED;
+  p->state_time  = time(NULL);
+  p->accepting   = 0;
+  p->shared      = DefaultShared;
+  p->filetype    = mimeAddType(MimeDatabase, "printer", name);
 
   cupsdSetString(&p->job_sheets[0], "none");
   cupsdSetString(&p->job_sheets[1], "none");
@@ -164,9 +118,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...
   */
@@ -198,8 +149,32 @@ cupsdCreateCommonData(void)
   struct statfs                spoolinfo;      /* FS info for spool directory */
   double               spoolsize;      /* FS size */
 #endif /* HAVE_STATVFS */
-  static const int nups[] =            /* number-up-supported values */
+  static const char * const page_delivery[] =
+               {                       /* page-delivery-supported values */
+                 "reverse-order",
+                 "same-order"
+               };
+  static const char * const print_scaling[] =
+               {                       /* print-scaling-supported values */
+                 "auto",
+                 "auto-fit",
+                 "fill",
+                 "fit",
+                 "none"
+               };
+  static const int number_up[] =               /* number-up-supported values */
                { 1, 2, 4, 6, 9, 16 };
+  static const char * const number_up_layout[] =
+               {                       /* number-up-layout-supported values */
+                 "btlr",
+                 "btrl",
+                 "lrbt",
+                 "lrtb",
+                 "rlbt",
+                 "rltb",
+                 "tblr",
+                 "tbrl"
+               };
   static const int orients[4] =/* orientation-requested-supported values */
                {
                  IPP_PORTRAIT,
@@ -218,6 +193,10 @@ cupsdCreateCommonData(void)
                  "third-shift",
                  "weekend"
                };
+  static const char * const features[] =/* ipp-features-supported values */
+               {
+                 "subscription-object"
+               };
   static const char * const versions[] =/* ipp-versions-supported values */
                {
                  "1.0",
@@ -227,54 +206,53 @@ cupsdCreateCommonData(void)
                };
   static const int     ops[] =         /* operations-supported values */
                {
-                 IPP_PRINT_JOB,
-                 IPP_VALIDATE_JOB,
-                 IPP_CREATE_JOB,
-                 IPP_SEND_DOCUMENT,
-                 IPP_CANCEL_JOB,
-                 IPP_GET_JOB_ATTRIBUTES,
-                 IPP_GET_JOBS,
-                 IPP_GET_PRINTER_ATTRIBUTES,
-                 IPP_HOLD_JOB,
-                 IPP_RELEASE_JOB,
-                 IPP_RESTART_JOB,
-                 IPP_PAUSE_PRINTER,
-                 IPP_RESUME_PRINTER,
-                 IPP_PURGE_JOBS,
-                 IPP_SET_PRINTER_ATTRIBUTES,
-                 IPP_SET_JOB_ATTRIBUTES,
-                 IPP_GET_PRINTER_SUPPORTED_VALUES,
-                 IPP_CREATE_PRINTER_SUBSCRIPTION,
-                 IPP_CREATE_JOB_SUBSCRIPTION,
-                 IPP_GET_SUBSCRIPTION_ATTRIBUTES,
-                 IPP_GET_SUBSCRIPTIONS,
-                 IPP_RENEW_SUBSCRIPTION,
-                 IPP_CANCEL_SUBSCRIPTION,
-                 IPP_GET_NOTIFICATIONS,
-                 IPP_ENABLE_PRINTER,
-                 IPP_DISABLE_PRINTER,
-                 IPP_HOLD_NEW_JOBS,
-                 IPP_RELEASE_HELD_NEW_JOBS,
-                 IPP_CANCEL_JOBS,
-                 IPP_CANCEL_MY_JOBS,
-                 IPP_CLOSE_JOB,
-                 CUPS_GET_DEFAULT,
-                 CUPS_GET_PRINTERS,
-                 CUPS_ADD_PRINTER,
-                 CUPS_DELETE_PRINTER,
-                 CUPS_GET_CLASSES,
-                 CUPS_ADD_CLASS,
-                 CUPS_DELETE_CLASS,
-                 CUPS_ACCEPT_JOBS,
-                 CUPS_REJECT_JOBS,
-                 CUPS_SET_DEFAULT,
-                 CUPS_GET_DEVICES,
-                 CUPS_GET_PPDS,
-                 CUPS_MOVE_JOB,
-                 CUPS_AUTHENTICATE_JOB,
-                 CUPS_GET_PPD,
-                 CUPS_GET_DOCUMENT,
-                 IPP_RESTART_JOB
+                 IPP_OP_PRINT_JOB,
+                 IPP_OP_VALIDATE_JOB,
+                 IPP_OP_CREATE_JOB,
+                 IPP_OP_SEND_DOCUMENT,
+                 IPP_OP_CANCEL_JOB,
+                 IPP_OP_GET_JOB_ATTRIBUTES,
+                 IPP_OP_GET_JOBS,
+                 IPP_OP_GET_PRINTER_ATTRIBUTES,
+                 IPP_OP_HOLD_JOB,
+                 IPP_OP_RELEASE_JOB,
+                 IPP_OP_PAUSE_PRINTER,
+                 IPP_OP_RESUME_PRINTER,
+                 IPP_OP_PURGE_JOBS,
+                 IPP_OP_SET_PRINTER_ATTRIBUTES,
+                 IPP_OP_SET_JOB_ATTRIBUTES,
+                 IPP_OP_GET_PRINTER_SUPPORTED_VALUES,
+                 IPP_OP_CREATE_PRINTER_SUBSCRIPTIONS,
+                 IPP_OP_CREATE_JOB_SUBSCRIPTIONS,
+                 IPP_OP_GET_SUBSCRIPTION_ATTRIBUTES,
+                 IPP_OP_GET_SUBSCRIPTIONS,
+                 IPP_OP_RENEW_SUBSCRIPTION,
+                 IPP_OP_CANCEL_SUBSCRIPTION,
+                 IPP_OP_GET_NOTIFICATIONS,
+                 IPP_OP_ENABLE_PRINTER,
+                 IPP_OP_DISABLE_PRINTER,
+                 IPP_OP_HOLD_NEW_JOBS,
+                 IPP_OP_RELEASE_HELD_NEW_JOBS,
+                 IPP_OP_CANCEL_JOBS,
+                 IPP_OP_CANCEL_MY_JOBS,
+                 IPP_OP_CLOSE_JOB,
+                 IPP_OP_CUPS_GET_DEFAULT,
+                 IPP_OP_CUPS_GET_PRINTERS,
+                 IPP_OP_CUPS_ADD_MODIFY_PRINTER,
+                 IPP_OP_CUPS_DELETE_PRINTER,
+                 IPP_OP_CUPS_GET_CLASSES,
+                 IPP_OP_CUPS_ADD_MODIFY_CLASS,
+                 IPP_OP_CUPS_DELETE_CLASS,
+                 IPP_OP_CUPS_ACCEPT_JOBS,
+                 IPP_OP_CUPS_REJECT_JOBS,
+                 IPP_OP_CUPS_SET_DEFAULT,
+                 IPP_OP_CUPS_GET_DEVICES,
+                 IPP_OP_CUPS_GET_PPDS,
+                 IPP_OP_CUPS_MOVE_JOB,
+                 IPP_OP_CUPS_AUTHENTICATE_JOB,
+                 IPP_OP_CUPS_GET_PPD,
+                 IPP_OP_CUPS_GET_DOCUMENT,
+                 IPP_OP_RESTART_JOB
                };
   static const char * const charsets[] =/* charset-supported values */
                {
@@ -337,6 +315,7 @@ cupsdCreateCommonData(void)
                {                       /* job-creation-attributes-supported */
                  "copies",
                  "finishings",
+                 "finishings-col",
                  "ipp-attribute-fidelity",
                  "job-hold-until",
                  "job-name",
@@ -346,11 +325,14 @@ cupsdCreateCommonData(void)
                  "media-col",
                  "multiple-document-handling",
                  "number-up",
-                 "output-bin",
-                 "output-mode",
+                 "number-up-layout",
                  "orientation-requested",
+                 "output-bin",
+                 "page-delivery",
                  "page-ranges",
+                 "print-color-mode",
                  "print-quality",
+                 "print-scaling",
                  "printer-resolution",
                  "sides"
                };
@@ -366,9 +348,9 @@ cupsdCreateCommonData(void)
                  "multiple-document-handling",
                  "number-up",
                  "output-bin",
-                 "output-mode",
                  "orientation-requested",
                  "page-ranges",
+                 "print-color-mode",
                  "print-quality",
                  "printer-resolution",
                  "sides"
@@ -387,8 +369,11 @@ cupsdCreateCommonData(void)
                };
   static const char * const printer_settable[] =
                {                       /* printer-settable-attributes-supported */
+                 "printer-geo-location",
                  "printer-info",
-                 "printer-location"
+                 "printer-location",
+                 "printer-organization",
+                 "printer-organizational-unit"
                };
   static const char * const which_jobs[] =
                {                       /* which-jobs-supported values */
@@ -468,6 +453,9 @@ cupsdCreateCommonData(void)
   ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
                "generated-natural-language-supported", NULL, DefaultLanguage);
 
+  /* ipp-features-supported */
+  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "ipp-features-supported", sizeof(features) / sizeof(features[0]), NULL, features);
+
   /* ipp-versions-supported */
   ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
                 "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]),
@@ -477,6 +465,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",
@@ -492,8 +484,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,
@@ -577,6 +569,9 @@ cupsdCreateCommonData(void)
   ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
                 "multiple-operation-time-out", MultipleOperationTimeout);
 
+  /* multiple-operation-time-out-action */
+  ippAddString(CommonData, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "multiple-operation-time-out-action", NULL, "process-job");
+
   /* natural-language-configured (no IPP_TAG_COPY) */
   ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
                "natural-language-configured", NULL, DefaultLanguage);
@@ -635,17 +630,22 @@ cupsdCreateCommonData(void)
 
   /* number-up-supported */
   ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-                 "number-up-supported", sizeof(nups) / sizeof(nups[0]), nups);
+                 "number-up-supported", sizeof(number_up) / sizeof(number_up[0]), number_up);
+
+  /* number-up-layout-supported */
+  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "number-up-layout-supported", sizeof(number_up_layout) / sizeof(number_up_layout[0]), NULL, number_up_layout);
 
   /* 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,
                  "orientation-requested-supported", 4, orients);
 
+  /* page-delivery-supported */
+  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "page-delivery-supported", sizeof(page_delivery) / sizeof(page_delivery[0]), NULL, page_delivery);
+
   /* page-ranges-supported */
   ippAddBoolean(CommonData, IPP_TAG_PRINTER, "page-ranges-supported", 1);
 
@@ -663,6 +663,12 @@ cupsdCreateCommonData(void)
   ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
                "pdl-override-supported", NULL, "attempted");
 
+  /* print-scaling-supported */
+  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-scaling-supported", sizeof(print_scaling) / sizeof(print_scaling[0]), NULL, print_scaling);
+
+  /* printer-get-attributes-supported */
+  ippAddString(CommonData, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "printer-get-attributes-supported", NULL, "document-format");
+
   /* printer-op-policy-supported */
   attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
                        "printer-op-policy-supported", cupsArrayCount(Policies),
@@ -720,9 +726,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)",
@@ -747,16 +750,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...
   */
@@ -765,80 +758,54 @@ 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...
+  * If p is the default printer, assign a different one...
   */
 
-#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);
+  if (p == DefaultPrinter)
+    DefaultPrinter = NULL;
 
-  snprintf(filename, sizeof(filename), "/var/spool/lp/activeicons/%s", p->name);
-  unlink(filename);
+ /*
+  * Remove this printer from any classes...
+  */
 
-  snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.config", p->name);
-  unlink(filename);
+  changed = cupsdDeletePrinterFromClasses(p);
 
-  snprintf(filename, sizeof(filename), "/var/spool/lp/pod/%s.status", p->name);
-  unlink(filename);
+ /*
+  * Deregister from any browse protocols...
+  */
 
-  snprintf(filename, sizeof(filename), "/var/spool/lp/member/%s", p->name);
-  unlink(filename);
-#endif /* __sgi */
+  cupsdDeregisterPrinter(p, 1);
 
  /*
-  * If p is the default printer, assign a different one...
+  * Remove support files if this is a temporary queue and deregister color
+  * profiles...
   */
 
-  if (p == DefaultPrinter)
+  if (p->temporary)
   {
-    DefaultPrinter = NULL;
-
-    if (UseNetworkDefault)
-    {
-     /*
-      * Find the first network default printer and use it...
-      */
-
-      cupsd_printer_t  *dp;            /* New default printer */
+    char       filename[1024];         /* Script/PPD filename */
 
+   /*
+    * Remove any old PPD or script files...
+    */
 
-      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;
-       }
-    }
-  }
+    snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot, p->name);
+    unlink(filename);
+    snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd.O", ServerRoot, p->name);
+    unlink(filename);
 
- /*
-  * Remove this printer from any classes...
-  */
+    snprintf(filename, sizeof(filename), "%s/%s.png", CacheDir, p->name);
+    unlink(filename);
 
-  if (!(p->type & CUPS_PRINTER_IMPLICIT))
-  {
-    changed = cupsdDeletePrinterFromClasses(p);
+    snprintf(filename, sizeof(filename), "%s/%s.data", CacheDir, p->name);
+    unlink(filename);
 
    /*
-    * Deregister from any browse protocols...
+    * Unregister color profiles...
     */
 
-    cupsdDeregisterPrinter(p, 1);
+    cupsdUnregisterColor(p);
   }
 
  /*
@@ -866,6 +833,7 @@ cupsdDeletePrinter(
   cupsdClearString(&p->hostname);
   cupsdClearString(&p->name);
   cupsdClearString(&p->location);
+  cupsdClearString(&p->geo_location);
   cupsdClearString(&p->make_model);
   cupsdClearString(&p->info);
   cupsdClearString(&p->job_sheets[0]);
@@ -875,19 +843,18 @@ cupsdDeletePrinter(
   cupsdClearString(&p->port_monitor);
   cupsdClearString(&p->op_policy);
   cupsdClearString(&p->error_policy);
+  cupsdClearString(&p->strings);
 
   cupsdClearString(&p->alert);
   cupsdClearString(&p->alert_description);
 
-#ifdef HAVE_DNSSD
+#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);
@@ -902,6 +869,32 @@ cupsdDeletePrinter(
 }
 
 
+/*
+ * 'cupsdDeleteTemporaryPrinters()' - Delete unneeded temporary printers.
+ */
+
+void
+cupsdDeleteTemporaryPrinters(int force) /* I - Force deletion instead of auto? */
+{
+  cupsd_printer_t *p;                   /* Current printer */
+  time_t          unused_time;          /* Last time for printer state change */
+
+
+ /*
+  * Allow temporary printers to stick around for 60 seconds after the last job
+  * completes.
+  */
+
+  unused_time = time(NULL) - 60;
+
+  for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); p; p = (cupsd_printer_t *)cupsArrayNext(Printers))
+  {
+    if (p->temporary && (force || p->state_time < unused_time))
+      cupsdDeletePrinter(p, 0);
+  }
+}
+
+
 /*
  * 'cupsdFindDest()' - Find a destination in the list.
  */
@@ -971,8 +964,14 @@ cupsdLoadAllPrinters(void)
     * Decode the directive...
     */
 
-    if (!_cups_strcasecmp(line, "<Printer") ||
-        !_cups_strcasecmp(line, "<DefaultPrinter"))
+    if (!_cups_strcasecmp(line, "NextPrinterId"))
+    {
+      if (value && (i = atoi(value)) > 0)
+        NextPrinterId = i;
+      else
+        cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum);
+    }
+    else if (!_cups_strcasecmp(line, "<Printer") || !_cups_strcasecmp(line, "<DefaultPrinter"))
     {
      /*
       * <Printer name> or <DefaultPrinter name>
@@ -1001,7 +1000,7 @@ cupsdLoadAllPrinters(void)
         cupsdLogMessage(CUPSD_LOG_ERROR,
                        "Syntax error on line %d of printers.conf.", linenum);
     }
-    else if (!_cups_strcasecmp(line, "</Printer>"))
+    else if (!_cups_strcasecmp(line, "</Printer>") || !_cups_strcasecmp(line, "</DefaultPrinter>"))
     {
       if (p != NULL)
       {
@@ -1009,17 +1008,21 @@ cupsdLoadAllPrinters(void)
         * Close out the current printer...
        */
 
+        if (!p->printer_id)
+        {
+          p->printer_id = NextPrinterId ++;
+          cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
+       }
+
         cupsdSetPrinterAttrs(p);
 
-        if (strncmp(p->device_uri, "file:", 5) &&
-           p->state != IPP_PRINTER_STOPPED)
+        if (strncmp(p->device_uri, "file:", 5) && p->state != IPP_PRINTER_STOPPED)
        {
         /*
           * See if the backend exists...
          */
 
-         snprintf(line, sizeof(line), "%s/backend/%s", ServerBin,
-                  p->device_uri);
+         snprintf(line, sizeof(line), "%s/backend/%s", ServerBin, p->device_uri);
 
           if ((valueptr = strchr(line + strlen(ServerBin), ':')) != NULL)
            *valueptr = '\0';           /* Chop everything but URI scheme */
@@ -1031,8 +1034,7 @@ cupsdLoadAllPrinters(void)
            */
 
            p->state = IPP_PRINTER_STOPPED;
-           snprintf(p->state_message, sizeof(p->state_message),
-                    "Backend %s does not exist!", line);
+           snprintf(p->state_message, sizeof(p->state_message), "Backend %s does not exist!", line);
          }
         }
 
@@ -1047,6 +1049,13 @@ cupsdLoadAllPrinters(void)
       cupsdLogMessage(CUPSD_LOG_ERROR,
                       "Syntax error on line %d of printers.conf.", linenum);
     }
+    else if (!_cups_strcasecmp(line, "PrinterId"))
+    {
+      if (value && (i = atoi(value)) > 0)
+        p->printer_id = i;
+      else
+        cupsdLogMessage(CUPSD_LOG_ERROR, "Bad PrinterId on line %d of printers.conf.", linenum);
+    }
     else if (!_cups_strcasecmp(line, "UUID"))
     {
       if (value && !strncmp(value, "urn:uuid:", 9))
@@ -1077,6 +1086,21 @@ cupsdLoadAllPrinters(void)
       if (value)
        cupsdSetString(&p->location, value);
     }
+    else if (!_cups_strcasecmp(line, "GeoLocation"))
+    {
+      if (value)
+        cupsdSetString(&p->geo_location, value);
+    }
+    else if (!_cups_strcasecmp(line, "Organization"))
+    {
+      if (value)
+       cupsdSetString(&p->organization, value);
+    }
+    else if (!_cups_strcasecmp(line, "OrganizationalUnit"))
+    {
+      if (value)
+       cupsdSetString(&p->organizational_unit, value);
+    }
     else if (!_cups_strcasecmp(line, "DeviceURI"))
     {
       if (value)
@@ -1181,6 +1205,15 @@ cupsdLoadAllPrinters(void)
       if (value)
         p->state_time = atoi(value);
     }
+    else if (!_cups_strcasecmp(line, "ConfigTime"))
+    {
+     /*
+      * Set the config time...
+      */
+
+      if (value)
+        p->config_time = atoi(value);
+    }
     else if (!_cups_strcasecmp(line, "Accepting"))
     {
      /*
@@ -1204,7 +1237,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);
@@ -1331,10 +1364,17 @@ cupsdLoadAllPrinters(void)
     else if (!_cups_strcasecmp(line, "ErrorPolicy"))
     {
       if (value)
-        cupsdSetString(&p->error_policy, value);
+      {
+       if (strcmp(value, "retry-current-job") &&
+           strcmp(value, "abort-job") &&
+           strcmp(value, "retry-job") &&
+           strcmp(value, "stop-printer"))
+         cupsdLogMessage(CUPSD_LOG_ALERT, "Invalid ErrorPolicy \"%s\" on line %d or printers.conf.", ErrorPolicy, linenum);
+       else
+         cupsdSetString(&p->error_policy, value);
+      }
       else
-       cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "Syntax error on line %d of printers.conf.", linenum);
+       cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d of printers.conf.", linenum);
     }
     else if (!_cups_strcasecmp(line, "Attribute") && value)
     {
@@ -1392,14 +1432,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...
   */
@@ -1432,14 +1464,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);
-  }
 }
 
 
@@ -1488,6 +1512,8 @@ cupsdSaveAllPrinters(void)
   cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp);
   cupsFilePuts(fp, "# DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING\n");
 
+  cupsFilePrintf(fp, "NextPrinterId %d\n", NextPrinterId);
+
  /*
   * Write each local printer known to the system...
   */
@@ -1497,12 +1523,10 @@ cupsdSaveAllPrinters(void)
        printer = (cupsd_printer_t *)cupsArrayNext(Printers))
   {
    /*
-    * Skip remote destinations and printer classes...
+    * Skip printer classes and temporary queues...
     */
 
-    if ((printer->type & CUPS_PRINTER_DISCOVERED) ||
-        (printer->type & CUPS_PRINTER_CLASS) ||
-       (printer->type & CUPS_PRINTER_IMPLICIT))
+    if ((printer->type & CUPS_PRINTER_CLASS) || printer->temporary)
       continue;
 
    /*
@@ -1514,6 +1538,9 @@ cupsdSaveAllPrinters(void)
     else
       cupsFilePrintf(fp, "<Printer %s>\n", printer->name);
 
+    if (printer->printer_id)
+      cupsFilePrintf(fp, "PrinterId %d\n", printer->printer_id);
+
     cupsFilePrintf(fp, "UUID %s\n", printer->uuid);
 
     if (printer->num_auth_info_required > 0)
@@ -1548,9 +1575,18 @@ cupsdSaveAllPrinters(void)
     if (printer->location)
       cupsFilePutConf(fp, "Location", printer->location);
 
+    if (printer->geo_location)
+      cupsFilePutConf(fp, "GeoLocation", printer->geo_location);
+
     if (printer->make_model)
       cupsFilePutConf(fp, "MakeModel", printer->make_model);
 
+    if (printer->organization)
+      cupsFilePutConf(fp, "Organization", printer->organization);
+
+    if (printer->organizational_unit)
+      cupsFilePutConf(fp, "OrganizationalUnit", printer->organizational_unit);
+
     cupsFilePutConf(fp, "DeviceURI", printer->device_uri);
 
     if (printer->port_monitor)
@@ -1560,13 +1596,14 @@ cupsdSaveAllPrinters(void)
     {
       cupsFilePuts(fp, "State Stopped\n");
 
-      if (printer->state_message)
+      if (printer->state_message[0])
         cupsFilePutConf(fp, "StateMessage", printer->state_message);
     }
     else
       cupsFilePuts(fp, "State Idle\n");
 
     cupsFilePrintf(fp, "StateTime %d\n", (int)printer->state_time);
+    cupsFilePrintf(fp, "ConfigTime %d\n", (int)printer->config_time);
 
     for (i = 0; i < printer->num_reasons; i ++)
       if (strcmp(printer->reasons[i], "connecting-to-device") &&
@@ -1624,8 +1661,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);
       }
 
@@ -1684,8 +1720,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);
       }
 
@@ -1705,8 +1740,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);
       }
 
@@ -1718,15 +1752,10 @@ cupsdSaveAllPrinters(void)
       cupsFilePrintf(fp, "Attribute marker-change-time %ld\n",
                      (long)printer->marker_time);
 
-    cupsFilePuts(fp, "</Printer>\n");
-
-#ifdef __sgi
-    /*
-     * Make IRIX desktop & printer status happy
-     */
-
-    write_irix_state(printer);
-#endif /* __sgi */
+    if (printer == DefaultPrinter)
+      cupsFilePuts(fp, "</DefaultPrinter>\n");
+    else
+      cupsFilePuts(fp, "</Printer>\n");
   }
 
   cupsdCloseCreatedConfFile(fp, filename);
@@ -1829,7 +1858,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);
   }
@@ -1841,16 +1870,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"))
@@ -1982,12 +2001,15 @@ 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 */
 
 
@@ -2001,13 +2023,36 @@ 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, ptr = value;
-       (ptr = strchr(ptr, ',')) != NULL;
-       ptr ++, count ++);
+  for (count = 1, quote = '\0', ptr = temp;
+       *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...
@@ -2035,21 +2080,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
@@ -2085,21 +2131,113 @@ 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 = temp; i < count; i ++)
+    {
+      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;
+
+         if (ptr == start)
+           start ++;
+         else
+           _cups_strcpy(ptr, ptr + 1);
+       }
+       else if (*ptr == ',')
+       {
+         *ptr++ = '\0';
+         break;
+       }
+      }
+
+      attr->values[i].string.text = _cupsStrAlloc(start);
+    }
+  }
+
+  free(temp);
+
+ /*
+  * Update the printer-supply and printer-supply-description, as needed...
+  */
+
+  if (!strcmp(name, "marker-names"))
+  {
+    ipp_attribute_t *supply_desc = ippFindAttribute(p->attrs, "printer-supply-description", IPP_TAG_TEXT);
+                                       /* printer-supply-description attribute */
+
+    if (supply_desc != NULL)
+      ippDeleteAttribute(p->attrs, supply_desc);
+
+    supply_desc = ippCopyAttribute(p->attrs, attr, 0);
+    ippSetName(p->attrs, &supply_desc, "printer-supply-description");
+    ippSetValueTag(p->attrs, &supply_desc, IPP_TAG_TEXT);
+  }
+  else if (!strcmp(name, "marker-colors") || !strcmp(name, "marker-levels") || !strcmp(name, "marker-types"))
+  {
+    char       buffer[256],            /* printer-supply values */
+               pstype[64],             /* printer-supply type value */
+               *psptr;                 /* Pointer into type */
+    const char *color,                 /* marker-colors value */
+               *type;                  /* marker-types value */
+    int                level;                  /* marker-levels value */
+    ipp_attribute_t *colors = ippFindAttribute(p->attrs, "marker-colors", IPP_TAG_NAME);
+                                       /* marker-colors attribute */
+    ipp_attribute_t *levels = ippFindAttribute(p->attrs, "marker-levels", IPP_TAG_INTEGER);
+                                       /* marker-levels attribute */
+    ipp_attribute_t *types = ippFindAttribute(p->attrs, "marker-types", IPP_TAG_KEYWORD);
+                                       /* marker-types attribute */
+    ipp_attribute_t *supply = ippFindAttribute(p->attrs, "printer-supply", IPP_TAG_STRING);
+                                       /* printer-supply attribute */
+
+    if (supply != NULL)
+    {
+      ippDeleteAttribute(p->attrs, supply);
+      supply = NULL;
+    }
+
+    if (!colors || !levels || !types)
+      return;
+
+    count = ippGetCount(colors);
+    if (count != ippGetCount(levels) || count != ippGetCount(types))
+      return;
+
     for (i = 0; i < count; i ++)
     {
-      if ((ptr = strchr(value, ',')) != NULL)
-        *ptr++ = '\0';
+      color = ippGetString(colors, i, NULL);
+      level = ippGetInteger(levels, i);
+      type  = ippGetString(types, i, NULL);
 
-      attr->values[i].string.text = _cupsStrAlloc(value);
+      for (psptr = pstype; *type && psptr < (pstype + sizeof(pstype) - 1); type ++)
+        if (*type == '-')
+       {
+         type ++;
+         *psptr++ = (char)toupper(*type & 255);
+       }
+       else
+         *psptr++ = *type;
+      *psptr = '\0';
 
-      if (ptr)
-        value = ptr;
+      snprintf(buffer, sizeof(buffer), "index=%d;class=%s;type=%s;unit=percent;maxcapacity=100;level=%d;colorantname=%s;", i + 1, strncmp(pstype, "waste", 5) ? "supplyThatIsConsumed" : "receptacleThatIsFilled", pstype, level, color);
+
+      if (!i)
+        supply = ippAddOctetString(p->attrs, IPP_TAG_PRINTER, "printer-supply", buffer, (int)strlen(buffer));
+      else
+        ippSetOctetString(p->attrs, &supply, i, buffer, (int)strlen(buffer));
     }
   }
 }
@@ -2112,32 +2250,16 @@ 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 */
   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 */
-  cups_option_t        *option;                /* Current printer option */
   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,
-                p->type));
-
  /*
   * Make sure that we have the common attributes defined...
   */
@@ -2145,6 +2267,8 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
   if (!CommonData)
     cupsdCreateCommonData();
 
+  _cupsRWLockWrite(&p->lock);
+
  /*
   * Clear out old filters, if any...
   */
@@ -2156,20 +2280,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) &&
-           (p->type & CUPS_PRINTER_DISCOVERED))
-  {
-    num_air = 2;
-    air     = air_userpass;
-  }
 
   if (p->type & CUPS_PRINTER_CLASS)
     snprintf(resource, sizeof(resource), "/classes/%s", p->name);
@@ -2186,27 +2296,22 @@ 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)
+    if (auth_type == CUPSD_AUTH_BASIC)
       auth_supported = "basic";
-    else if (auth_type == CUPSD_AUTH_DIGEST)
-      auth_supported = "digest";
 #ifdef HAVE_GSSAPI
     else if (auth_type == CUPSD_AUTH_NEGOTIATE)
       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_ptype_t)~CUPS_PRINTER_AUTHENTICATED;
   }
-  else if (!(p->type & CUPS_PRINTER_DISCOVERED))
-    p->type &= ~CUPS_PRINTER_AUTHENTICATED;
+  else
+    p->type &= (cups_ptype_t)~CUPS_PRINTER_AUTHENTICATED;
 
  /*
   * Create the required IPP attributes for a printer...
@@ -2219,14 +2324,21 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
                "uri-authentication-supported", NULL, auth_supported);
   ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
                "uri-security-supported", NULL, "none");
+  if (p->printer_id)
+    ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "printer-id", p->printer_id);
   ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME, "printer-name", NULL,
                p->name);
   ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-location",
                NULL, p->location ? p->location : "");
+  if (p->geo_location)
+    ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-geo-location", NULL, p->geo_location);
+  else
+    ippAddOutOfBand(p->attrs, IPP_TAG_PRINTER, IPP_TAG_UNKNOWN, "printer-geo-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);
+  ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-organization", NULL, p->organization ? p->organization : "");
+  ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-organizational-unit", NULL, p->organizational_unit ? p->organizational_unit : "");
+  ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-uuid", NULL, p->uuid);
 
   if (cupsArrayCount(p->users) > 0)
   {
@@ -2242,7 +2354,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,
@@ -2251,10 +2363,12 @@ 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 && !(p->type & CUPS_PRINTER_DISCOVERED))
+  if (cupsArrayCount(Banners) > 0)
   {
    /*
     * Setup the job-sheets-default attribute...
@@ -2275,164 +2389,99 @@ 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_ptype_t)~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 = _cupsStrAlloc(p->printers[i]->name);
 
-      ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
-                  "printer-uri-supported", NULL, resource);
+       p->type &= (cups_ptype_t)~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
+      }
     }
-    else
-      ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
-                  "printer-uri-supported", NULL, p->uri);
-
-    ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info",
-                NULL, p->uri);
-
-    if (p->make_model)
-      ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
-                   "printer-make-and-model", NULL, p->make_model);
-
-    ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
-                p->uri);
-
-    p->raw    = 1;
-    p->remote = 1;
   }
   else
   {
    /*
-    * Assign additional attributes depending on whether this is a printer
-    * or class...
+    * Add printer-specific attributes...
     */
 
-    if (p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
-    {
-      p->raw = 1;
-      p->type &= ~CUPS_PRINTER_OPTIONS;
-
-     /*
-      * Add class-specific attributes...
-      */
-
-      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,
+                p->sanitized_device_uri);
 
-      ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "device-uri", NULL,
-                  "file:///dev/null");
+   /*
+    * Assign additional attributes from the PPD file (if any)...
+    */
 
-      if (p->num_printers > 0)
-      {
-       /*
-       * Add a list of member names; URIs are added in copy_printer_attrs...
-       */
+    load_ppd(p);
 
-       attr    = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NAME,
-                                "member-names", p->num_printers, NULL, NULL);
-        p->type |= CUPS_PRINTER_OPTIONS;
+   /*
+    * Add filters for printer...
+    */
 
-       for (i = 0; i < p->num_printers; i ++)
-       {
-          if (attr != NULL)
-            attr->values[i].string.text = _cupsStrRetain(p->printers[i]->name);
+    cupsdSetPrinterReasons(p, "-cups-missing-filter-warning,"
+                             "cups-insecure-filter-warning");
 
-         p->type &= ~CUPS_PRINTER_OPTIONS | p->printers[i]->type;
-        }
-      }
+    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
+    else if (!(p->type & CUPS_PRINTER_REMOTE))
     {
      /*
-      * 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)...
+      * Add a filter from application/vnd.cups-raw to printer/name to
+      * handle "raw" printing by users.
       */
 
-      load_ppd(p);
+      add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -");
 
      /*
-      * Add filters for printer...
+      * Add a PostScript filter, since this is still possibly PS printer.
       */
 
-      cupsdSetPrinterReasons(p, "-cups-missing-filter-warning,"
-                                "cups-insecure-filter-warning");
-
-      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 */
-
-
-       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!
-         */
-
-         snprintf(interface, sizeof(interface), "*/* 0 %s/interfaces/%s",
-                  ServerRoot, p->name);
-         add_printer_filter(p, p->filetype, interface);
-       }
-       else
-       {
-        /*
-         * Add a filter from application/vnd.cups-raw to printer/name to
-         * handle "raw" printing by users.
-         */
-
-         add_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -");
-
-        /*
-         * Add a PostScript filter, since this is still possibly PS printer.
-         */
-
-         add_printer_filter(p, p->filetype,
-                            "application/vnd.cups-postscript 0 -");
-       }
-      }
+      add_printer_filter(p, p->filetype,
+                        "application/vnd.cups-postscript 0 -");
+    }
 
-      if (p->pc && p->pc->prefilters)
-      {
-        if (!p->prefiltertype)
-          p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name);
+    if (p->pc && p->pc->prefilters)
+    {
+      if (!p->prefiltertype)
+       p->prefiltertype = mimeAddType(MimeDatabase, "prefilter", p->name);
 
-        for (filter = (char *)cupsArrayFirst(p->pc->prefilters);
-            filter;
-            filter = (char *)cupsArrayNext(p->pc->prefilters))
-         add_printer_filter(p, p->prefiltertype, filter);
-      }
+      for (filter = (char *)cupsArrayFirst(p->pc->prefilters);
+          filter;
+          filter = (char *)cupsArrayNext(p->pc->prefilters))
+       add_printer_filter(p, p->prefiltertype, filter);
     }
   }
 
@@ -2454,7 +2503,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);
       }
     }
 
@@ -2507,147 +2556,47 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
                                NULL)) != NULL)
       {
        for (i = 0; i < oldattr->num_values; i ++)
-         attr->values[i].string.text =
-             _cupsStrRetain(oldattr->values[i].string.text);
-      }
-    }
-
-    if ((oldattr = ippFindAttribute(oldattrs, "marker-types",
-                                    IPP_TAG_KEYWORD)) != NULL)
-    {
-      if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                                "marker-types", oldattr->num_values, NULL,
-                               NULL)) != NULL)
-      {
-       for (i = 0; i < oldattr->num_values; i ++)
-         attr->values[i].string.text =
-             _cupsStrRetain(oldattr->values[i].string.text);
-      }
-    }
-
-    ippDelete(oldattrs);
-  }
-
- /*
-  * Force sharing off for remote queues...
-  */
-
-  if (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT))
-    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);
+         attr->values[i].string.text =
+             _cupsStrAlloc(oldattr->values[i].string.text);
       }
+    }
 
-      for (i = p->num_options, option = p->options;
-           i > 0;
-          i --, option ++)
+    if ((oldattr = ippFindAttribute(oldattrs, "marker-types",
+                                    IPP_TAG_KEYWORD)) != NULL)
+    {
+      if ((attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                                "marker-types", oldattr->num_values, NULL,
+                               NULL)) != NULL)
       {
-        *attrptr++ = ' ';
-       strcpy(attrptr, option->name);
-       attrptr += strlen(attrptr);
-
-       if (option->value)
-       {
-         *attrptr++ = '=';
-
-          for (valptr = option->value; *valptr; valptr ++)
-         {
-           if (strchr(" \"\'\\", *valptr))
-             *attrptr++ = '\\';
-
-           *attrptr++ = *valptr;
-         }
-       }
+       for (i = 0; i < oldattr->num_values; i ++)
+         attr->values[i].string.text =
+             _cupsStrAlloc(oldattr->values[i].string.text);
       }
     }
+
+    ippDelete(oldattrs);
   }
 
+ /*
+  * Force sharing off for remote queues...
+  */
+
+  if (p->type & CUPS_PRINTER_REMOTE)
+    p->shared = 0;
+
  /*
   * Populate the document-format-supported attribute...
   */
 
   add_printer_formats(p);
 
-  DEBUG_printf(("cupsdSetPrinterAttrs: leaving name = %s, type = %x\n", p->name,
-                p->type));
-
  /*
   * Add name-default attributes...
   */
 
   add_printer_defaults(p);
 
-#ifdef __sgi
- /*
-  * Write the IRIX printer config and status files...
-  */
-
-  write_irix_config(p);
-  write_irix_state(p);
-#endif /* __sgi */
+  _cupsRWUnlock(&p->lock);
 
  /*
   * Let the browse protocols reflect the change
@@ -2744,14 +2693,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;
        }
     }
@@ -2782,6 +2734,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);
       }
@@ -2802,6 +2757,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 */
@@ -2811,13 +2767,6 @@ cupsdSetPrinterState(
   };
 
 
- /*
-  * Can't set status of remote printers...
-  */
-
-  if (p->type & CUPS_PRINTER_DISCOVERED)
-    return;
-
  /*
   * Set the new state...
   */
@@ -2837,13 +2786,7 @@ cupsdSetPrinterState(
     * Let the browse code know this needs to be updated...
     */
 
-    BrowseNext     = p;
-    p->state_time  = time(NULL);
-    p->browse_time = 0;
-
-#ifdef __sgi
-    write_irix_state(p);
-#endif /* __sgi */
+    p->state_time = time(NULL);
   }
 
  /*
@@ -2855,6 +2798,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...
   */
@@ -3037,22 +2991,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...
     */
@@ -3061,11 +2999,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);
   }
 }
 
@@ -3094,9 +3031,6 @@ cupsdValidateDest(
   int                  port;           /* Port portion of URI */
 
 
-  DEBUG_printf(("cupsdValidateDest(uri=\"%s\", dtype=%p, printer=%p)\n", uri,
-                dtype, printer));
-
  /*
   * Initialize return values...
   */
@@ -3158,8 +3092,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);
   }
@@ -3201,8 +3134,6 @@ cupsdValidateDest(
     }
   }
 
-  DEBUG_printf(("localized hostname is \"%s\"...\n", localname));
-
  /*
   * Find a matching printer or class...
   */
@@ -3217,8 +3148,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);
     }
@@ -3240,16 +3170,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.
   */
@@ -3443,13 +3363,18 @@ 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"));
     cupsArrayAdd(CommonDefaults, _cupsStrAlloc("media-col-default"));
+    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("notify-lease-duration-default"));
+    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("notify-events-default"));
     cupsArrayAdd(CommonDefaults, _cupsStrAlloc("number-up-default"));
-    cupsArrayAdd(CommonDefaults,
-                 _cupsStrAlloc("orientation-requested-default"));
+    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("orientation-requested-default"));
+    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("print-quality-default"));
   }
 
  /*
@@ -3491,6 +3416,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");
@@ -3594,7 +3523,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 != ')')
     {
@@ -3652,7 +3581,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
@@ -3767,7 +3696,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 */
@@ -3782,8 +3711,7 @@ add_printer_formats(cupsd_printer_t *p)   /* I - Printer */
         filter;
         filter = (mime_filter_t *)cupsArrayNext(MimeDatabase->filters))
     {
-      if (filter->dst == p->filetype && filter->filter &&
-         strstr(filter->filter, "PrintJobMgr"))
+      if (filter->dst == p->filetype && strstr(filter->filter, "PrintJobMgr"))
        break;
     }
 
@@ -3823,7 +3751,7 @@ add_printer_formats(cupsd_printer_t *p)   /* I - Printer */
 
     cupsdSetString(&p->pdl, pdl);
   }
-#endif /* HAVE_DNSSD */
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
 }
 
 
@@ -3901,9 +3829,7 @@ delete_printer_filters(
 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);
@@ -3926,6 +3852,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
   ppd_file_t   *ppd;                   /* PPD file */
   char         ppd_name[1024];         /* PPD filename */
   struct stat  ppd_info;               /* PPD file info */
+  char         strings_name[1024];     /* Strings filename */
   int          num_media;              /* Number of media options */
   ppd_size_t   *size;                  /* Current PPD size */
   ppd_option_t *duplex,                /* Duplex option */
@@ -3939,18 +3866,25 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
   int          xdpi,                   /* Horizontal resolution */
                ydpi;                   /* Vertical resolution */
   const char   *resptr;                /* Pointer into resolution keyword */
-  _pwg_size_t  *pwgsize;               /* Current PWG size */
-  _pwg_map_t   *pwgsource,             /* Current PWG source */
+  pwg_size_t   *pwgsize;               /* Current PWG size */
+  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 */
+               finishings[100];        /* 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 */
+  const char   *filter,                /* Current filter */
+               *mandatory;             /* Current mandatory attribute */
+  static const char * const pwg_raster_document_types[] =
+               {
+                 "black_1",
+                 "sgray_8",
+                 "srgb_8"
+               };
   static const char * const sides[3] = /* sides-supported values */
                {
                  "one-sided",
@@ -3977,6 +3911,8 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
   if (stat(ppd_name, &ppd_info))
     ppd_info.st_mtime = 1;
 
+  snprintf(strings_name, sizeof(strings_name), "%s/%s.strings", CacheDir, p->name);
+
   ippDelete(p->ppd_attrs);
   p->ppd_attrs = NULL;
 
@@ -4006,7 +3942,9 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
 
   cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", ppd_name);
 
-  p->type &= ~CUPS_PRINTER_OPTIONS;
+  cupsdClearString(&(p->make_model));
+
+  p->type &= (cups_ptype_t)~CUPS_PRINTER_OPTIONS;
   p->type |= CUPS_PRINTER_BW;
 
   finishings[0]  = IPP_FINISHINGS_NONE;
@@ -4014,7 +3952,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
 
   p->ppd_attrs = ippNew();
 
-  if ((ppd = ppdOpenFile(ppd_name)) != NULL)
+  if ((ppd = _ppdOpenFile(ppd_name, _PPD_LOCALIZATION_NONE)) != NULL)
   {
    /*
     * Add make/model and other various attributes...
@@ -4022,6 +3960,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)
@@ -4034,8 +3976,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,
@@ -4057,6 +4019,9 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
                      "pages-per-minute-color", 1);
     }
 
+    if ((ppd_attr = ppdFindAttr(ppd, "1284DeviceId", NULL)) != NULL)
+      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-device-id", NULL, ppd_attr->value);
+
     num_qualities = 0;
 
     if ((output_mode = ppdFindOption(ppd, "OutputMode")) != NULL)
@@ -4119,16 +4084,24 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
     ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
                 "printer-make-and-model", NULL, p->make_model);
 
+    if (p->pc && p->pc->strings)
+      _cupsMessageSave(strings_name, _CUPS_MESSAGE_STRINGS, p->pc->strings);
+
+    if (!access(strings_name, R_OK))
+      cupsdSetString(&p->strings, strings_name);
+    else
+      cupsdClearString(&p->strings);
+
    /*
     * Add media options from the PPD file...
     */
 
     if (ppd->num_sizes == 0 || !p->pc)
     {
-      if (!ppdFindAttr(ppd, "APScannerOnly", NULL))
+      if (!ppdFindAttr(ppd, "APScannerOnly", NULL) && !ppdFindAttr(ppd, "cups3D", NULL))
        cupsdLogMessage(CUPSD_LOG_CRIT,
                        "The PPD file for printer %s contains no media "
-                       "options and is therefore invalid!", p->name);
+                       "options and is therefore invalid.", p->name);
 
       ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
                   "media-default", NULL, "unknown");
@@ -4161,17 +4134,10 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
        input_slot = ppdFindMarkedChoice(ppd, "InputSlot");
        media_type = ppdFindMarkedChoice(ppd, "MediaType");
        col        = new_media_col(pwgsize,
-                                  input_slot ?
-                                      _ppdCacheGetSource(p->pc,
-                                                         input_slot->choice) :
-                                      NULL,
-                                  media_type ?
-                                      _ppdCacheGetType(p->pc,
-                                                       media_type->choice) :
-                                      NULL);
-
-       ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-default",
-                        col);
+                                  input_slot ? _ppdCacheGetSource(p->pc, input_slot->choice) : NULL,
+                                  media_type ? _ppdCacheGetType(p->pc, media_type->choice) : NULL);
+
+       ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-default", col);
         ippDelete(col);
       }
 
@@ -4192,13 +4158,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);
         }
       }
 
@@ -4215,7 +4216,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);
       }
 
      /*
@@ -4231,7 +4232,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);
       }
 
      /*
@@ -4476,38 +4477,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");
+      ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "pwg-raster-document-type-supported", 3, NULL, pwg_raster_document_types);
     }
     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");
+      ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "pwg-raster-document-type-supported", 2, NULL, pwg_raster_document_types);
+    }
+
+   /*
+    * 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);
     }
 
    /*
@@ -4525,10 +4538,7 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
       * Report all supported resolutions...
       */
 
-      attr = ippAddResolutions(p->ppd_attrs, IPP_TAG_PRINTER,
-                               "printer-resolution-supported",
-                               resolution->num_choices, IPP_RES_PER_INCH,
-                              NULL, NULL);
+      attr = ippAddResolutions(p->ppd_attrs, IPP_TAG_PRINTER, "printer-resolution-supported", resolution->num_choices, IPP_RES_PER_INCH, NULL, NULL);
 
       for (i = 0, choice = resolution->choices;
            i < resolution->num_choices;
@@ -4551,9 +4561,10 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
         attr->values[i].resolution.units = IPP_RES_PER_INCH;
 
         if (choice->marked)
-         ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
-                          "printer-resolution-default", IPP_RES_PER_INCH,
-                          xdpi, ydpi);
+         ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, "printer-resolution-default", IPP_RES_PER_INCH, xdpi, ydpi);
+
+        if (i == 0)
+         ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", IPP_RES_PER_INCH, xdpi, ydpi);
       }
     }
     else if ((ppd_attr = ppdFindAttr(ppd, "DefaultResolution", NULL)) != NULL &&
@@ -4586,6 +4597,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
       ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
                       "printer-resolution-supported", IPP_RES_PER_INCH,
                       xdpi, ydpi);
+      ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", IPP_RES_PER_INCH, xdpi, ydpi);
     }
     else
     {
@@ -4599,6 +4611,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
       ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
                       "printer-resolution-supported", IPP_RES_PER_INCH,
                       300, 300);
+      ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", IPP_RES_PER_INCH, 300, 300);
     }
 
    /*
@@ -4618,6 +4631,8 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
     {
       p->type |= CUPS_PRINTER_DUPLEX;
 
+      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "pwg-raster-document-sheet-back", NULL, "normal");
+
       ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
                    "sides-supported", 3, NULL, sides);
 
@@ -4642,16 +4657,90 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
     if (ppdFindOption(ppd, "Collate") != NULL)
       p->type |= CUPS_PRINTER_COLLATE;
 
-    if (ppdFindOption(ppd, "StapleLocation") != NULL)
+    if (p->pc && p->pc->finishings)
     {
-      p->type |= CUPS_PRINTER_STAPLE;
-      finishings[num_finishings++] = IPP_FINISHINGS_STAPLE;
+      _pwg_finishings_t        *fin;           /* Current finishing value */
+
+      for (fin = (_pwg_finishings_t *)cupsArrayFirst(p->pc->finishings); fin; fin = (_pwg_finishings_t *)cupsArrayNext(p->pc->finishings))
+      {
+        if (num_finishings < (int)(sizeof(finishings) / sizeof(finishings[0])))
+          finishings[num_finishings++] = fin->value;
+
+        switch (fin->value)
+        {
+          case IPP_FINISHINGS_BIND :
+          case IPP_FINISHINGS_BIND_LEFT :
+          case IPP_FINISHINGS_BIND_TOP :
+          case IPP_FINISHINGS_BIND_RIGHT :
+          case IPP_FINISHINGS_BIND_BOTTOM :
+          case IPP_FINISHINGS_EDGE_STITCH :
+          case IPP_FINISHINGS_EDGE_STITCH_LEFT :
+          case IPP_FINISHINGS_EDGE_STITCH_TOP :
+          case IPP_FINISHINGS_EDGE_STITCH_RIGHT :
+          case IPP_FINISHINGS_EDGE_STITCH_BOTTOM :
+              p->type |= CUPS_PRINTER_BIND;
+              break;
+
+          case IPP_FINISHINGS_COVER :
+              p->type |= CUPS_PRINTER_COVER;
+              break;
+
+          case IPP_FINISHINGS_PUNCH :
+          case IPP_FINISHINGS_PUNCH_TOP_LEFT :
+          case IPP_FINISHINGS_PUNCH_BOTTOM_LEFT :
+          case IPP_FINISHINGS_PUNCH_TOP_RIGHT :
+          case IPP_FINISHINGS_PUNCH_BOTTOM_RIGHT :
+          case IPP_FINISHINGS_PUNCH_DUAL_LEFT :
+          case IPP_FINISHINGS_PUNCH_DUAL_TOP :
+          case IPP_FINISHINGS_PUNCH_DUAL_RIGHT :
+          case IPP_FINISHINGS_PUNCH_DUAL_BOTTOM :
+          case IPP_FINISHINGS_PUNCH_TRIPLE_LEFT :
+          case IPP_FINISHINGS_PUNCH_TRIPLE_TOP :
+          case IPP_FINISHINGS_PUNCH_TRIPLE_RIGHT :
+          case IPP_FINISHINGS_PUNCH_TRIPLE_BOTTOM :
+          case IPP_FINISHINGS_PUNCH_QUAD_LEFT :
+          case IPP_FINISHINGS_PUNCH_QUAD_TOP :
+          case IPP_FINISHINGS_PUNCH_QUAD_RIGHT :
+          case IPP_FINISHINGS_PUNCH_QUAD_BOTTOM :
+              p->type |= CUPS_PRINTER_PUNCH;
+              break;
+
+          case IPP_FINISHINGS_STAPLE :
+          case IPP_FINISHINGS_STAPLE_TOP_LEFT :
+          case IPP_FINISHINGS_STAPLE_BOTTOM_LEFT :
+          case IPP_FINISHINGS_STAPLE_TOP_RIGHT :
+          case IPP_FINISHINGS_STAPLE_BOTTOM_RIGHT :
+          case IPP_FINISHINGS_STAPLE_DUAL_LEFT :
+          case IPP_FINISHINGS_STAPLE_DUAL_TOP :
+          case IPP_FINISHINGS_STAPLE_DUAL_RIGHT :
+          case IPP_FINISHINGS_STAPLE_DUAL_BOTTOM :
+          case IPP_FINISHINGS_STAPLE_TRIPLE_LEFT :
+          case IPP_FINISHINGS_STAPLE_TRIPLE_TOP :
+          case IPP_FINISHINGS_STAPLE_TRIPLE_RIGHT :
+          case IPP_FINISHINGS_STAPLE_TRIPLE_BOTTOM :
+              p->type |= CUPS_PRINTER_STAPLE;
+              break;
+
+          default :
+              break;
+        }
+      }
     }
 
-    if (ppdFindOption(ppd, "BindEdge") != NULL)
+    if (p->pc && p->pc->templates)
     {
-      p->type |= CUPS_PRINTER_BIND;
-      finishings[num_finishings++] = IPP_FINISHINGS_BIND;
+      const char       *template;      /* Finishing template */
+      ipp_attribute_t  *fin_col_db;    /* finishings-col-database attribute */
+      ipp_t            *fin_col;       /* finishings-col value */
+
+      fin_col_db = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER, "finishings-col-database", cupsArrayCount(p->pc->templates), NULL);
+      for (i = 0, template = (const char *)cupsArrayFirst(p->pc->templates); template; i ++, template = (const char *)cupsArrayNext(p->pc->templates))
+      {
+        fin_col = ippNew();
+        ippAddString(fin_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "finishing-template", NULL, template);
+        ippSetCollection(p->ppd_attrs, &fin_col_db, i, fin_col);
+        ippDelete(fin_col);
+      }
     }
 
     for (i = 0; i < ppd->num_sizes; i ++)
@@ -4838,22 +4927,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;
 
@@ -4957,14 +5040,12 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
 
     pstatus = ppdLastError(&pline);
 
-    cupsdLogMessage(CUPSD_LOG_ERROR, "PPD file for %s cannot be loaded!",
-                   p->name);
+    cupsdLogMessage(CUPSD_LOG_ERROR, "PPD file for %s cannot be loaded.", p->name);
 
     if (pstatus <= PPD_ALLOC_ERROR)
-      cupsdLogMessage(CUPSD_LOG_ERROR, "%s", strerror(errno));
+      cupsdLogMessage(CUPSD_LOG_ERROR, "%s: %s", ppd_name, strerror(errno));
     else
-      cupsdLogMessage(CUPSD_LOG_ERROR, "%s on line %d.",
-                     ppdErrorString(pstatus), pline);
+      cupsdLogMessage(CUPSD_LOG_ERROR, "%s on line %d of %s.", ppdErrorString(pstatus), pline, ppd_name);
 
     cupsdLogMessage(CUPSD_LOG_INFO,
                    "Hint: Run \"cupstestppd %s\" and fix any errors.",
@@ -4972,31 +5053,13 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
   }
   else
   {
-   /*
-    * If we have an interface script, add a filter entry for it...
-    */
-
-    char       interface[1024];        /* Interface script */
-
-
-    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!
-      */
-
-      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
-                  "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"))))
+    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.
@@ -5004,31 +5067,6 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
 
       p->type |= CUPS_PRINTER_REMOTE;
 
-     /*
-      * Point the printer-uri-supported attribute to the
-      * remote printer...
-      */
-
-      if (strchr(p->device_uri, '?'))
-      {
-       /*
-       * Strip trailing "?options" from URI...
-       */
-
-       char    resource[HTTP_MAX_URI], /* New URI */
-               *ptr;                   /* Pointer into URI */
-
-       strlcpy(resource, p->device_uri, sizeof(resource));
-       if ((ptr = strchr(resource, '?')) != NULL)
-         *ptr = '\0';
-
-       ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
-                    "printer-uri-supported", NULL, resource);
-      }
-      else
-       ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI,
-                    "printer-uri-supported", NULL, p->device_uri);
-
      /*
       * Then set the make-and-model accordingly...
       */
@@ -5089,7 +5127,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
  */
 
 static ipp_t *                         /* O - Collection value */
-new_media_col(_pwg_size_t *size,       /* I - media-size/margin values */
+new_media_col(pwg_size_t *size,        /* I - media-size/margin values */
               const char  *source,     /* I - media-source value */
               const char  *type)       /* I - media-type value */
 {
@@ -5128,261 +5166,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.
  */
@@ -5402,7 +5185,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;
@@ -5410,7 +5193,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;
@@ -5420,8 +5203,3 @@ write_xml_string(cups_file_t *fp, /* I - File to write to */
   if (s > start)
     cupsFilePuts(fp, start);
 }
-
-
-/*
- * End of "$Id: printers.c 7968 2008-09-19 23:03:01Z mike $".
- */