]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/printers.c
Fix parentheses in cupsdCleanJobs.
[thirdparty/cups.git] / scheduler / printers.c
index 86b3e5939cb06e2aca715aa83d6467099759605f..e4841c0713cd2580fe1345d3385be05ecd352b8c 100644 (file)
@@ -1,16 +1,11 @@
 /*
- * "$Id$"
- *
  * Printer routines for the CUPS scheduler.
  *
- * Copyright 2007-2015 by Apple Inc.
- * Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ * Copyright © 2007-2019 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/".
+ * Licensed under Apache License v2.0.  See the file "LICENSE" for more
+ * information.
  */
 
 /*
@@ -50,8 +45,7 @@ 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,
-                              const char *type);
+static ipp_t   *new_media_col(pwg_size_t *size);
 static void    write_xml_string(cups_file_t *fp, const char *s);
 
 
@@ -84,6 +78,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);
@@ -152,8 +148,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,
@@ -294,6 +314,7 @@ cupsdCreateCommonData(void)
                {                       /* job-creation-attributes-supported */
                  "copies",
                  "finishings",
+                 "finishings-col",
                  "ipp-attribute-fidelity",
                  "job-hold-until",
                  "job-name",
@@ -303,11 +324,14 @@ cupsdCreateCommonData(void)
                  "media-col",
                  "multiple-document-handling",
                  "number-up",
-                 "output-bin",
+                 "number-up-layout",
                  "orientation-requested",
+                 "output-bin",
+                 "page-delivery",
                  "page-ranges",
                  "print-color-mode",
                  "print-quality",
+                 "print-scaling",
                  "printer-resolution",
                  "sides"
                };
@@ -605,7 +629,10 @@ 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,
@@ -615,6 +642,9 @@ cupsdCreateCommonData(void)
   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);
 
@@ -632,6 +662,9 @@ 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");
 
@@ -743,6 +776,37 @@ cupsdDeletePrinter(
 
   cupsdDeregisterPrinter(p, 1);
 
+ /*
+  * Remove support files if this is a temporary queue and deregister color
+  * profiles...
+  */
+
+  if (p->temporary)
+  {
+    char       filename[1024];         /* Script/PPD filename */
+
+   /*
+    * Remove any old PPD or script files...
+    */
+
+    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);
+
+    snprintf(filename, sizeof(filename), "%s/%s.png", CacheDir, p->name);
+    unlink(filename);
+
+    snprintf(filename, sizeof(filename), "%s/%s.data", CacheDir, p->name);
+    unlink(filename);
+
+   /*
+    * Unregister color profiles...
+    */
+
+    cupsdUnregisterColor(p);
+  }
+
  /*
   * Free all memory used by the printer...
   */
@@ -778,6 +842,7 @@ cupsdDeletePrinter(
   cupsdClearString(&p->port_monitor);
   cupsdClearString(&p->op_policy);
   cupsdClearString(&p->error_policy);
+  cupsdClearString(&p->strings);
 
   cupsdClearString(&p->alert);
   cupsdClearString(&p->alert_description);
@@ -803,6 +868,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.
  */
@@ -872,8 +963,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>
@@ -910,17 +1007,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 */
@@ -932,8 +1033,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);
          }
         }
 
@@ -948,6 +1048,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))
@@ -1404,6 +1511,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...
   */
@@ -1413,10 +1522,10 @@ cupsdSaveAllPrinters(void)
        printer = (cupsd_printer_t *)cupsArrayNext(Printers))
   {
    /*
-    * Skip printer classes...
+    * Skip printer classes and temporary queues...
     */
 
-    if (printer->type & CUPS_PRINTER_CLASS)
+    if ((printer->type & CUPS_PRINTER_CLASS) || printer->temporary)
       continue;
 
    /*
@@ -1428,6 +1537,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)
@@ -2147,9 +2259,6 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
                *filter;                /* Current filter */
 
 
-  DEBUG_printf(("cupsdSetPrinterAttrs: entering name = %s, type = %x\n", p->name,
-                p->type));
-
  /*
   * Make sure that we have the common attributes defined...
   */
@@ -2157,6 +2266,8 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
   if (!CommonData)
     cupsdCreateCommonData();
 
+  _cupsRWLockWrite(&p->lock);
+
  /*
   * Clear out old filters, if any...
   */
@@ -2212,6 +2323,8 @@ 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",
@@ -2344,37 +2457,19 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
     }
     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 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_printer_filter(p, p->filetype, "application/vnd.cups-raw 0 -");
 
-       /*
-       * Add a PostScript filter, since this is still possibly PS printer.
-       */
+     /*
+      * 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)
@@ -2494,15 +2589,14 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
 
   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);
 
+  _cupsRWUnlock(&p->lock);
+
  /*
   * Let the browse protocols reflect the change
   */
@@ -2936,9 +3030,6 @@ cupsdValidateDest(
   int                  port;           /* Port portion of URI */
 
 
-  DEBUG_printf(("cupsdValidateDest(uri=\"%s\", dtype=%p, printer=%p)\n", uri,
-                dtype, printer));
-
  /*
   * Initialize return values...
   */
@@ -3042,8 +3133,6 @@ cupsdValidateDest(
     }
   }
 
-  DEBUG_printf(("localized hostname is \"%s\"...\n", localname));
-
  /*
   * Find a matching printer or class...
   */
@@ -3274,16 +3363,17 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */
     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-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"));
   }
 
  /*
@@ -3326,7 +3416,7 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */
                 "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,
+    ippAddInteger(p->attrs, IPP_TAG_PRINTER, MaxJobTime > 0 ? IPP_TAG_INTEGER : IPP_TAG_NOVALUE,
                  "job-cancel-after-default", MaxJobTime);
 
   if (!cupsGetOption("job-hold-until", p->num_options, p->options))
@@ -3755,38 +3845,43 @@ dirty_printer(cupsd_printer_t *p)       /* I - Printer */
 static void
 load_ppd(cupsd_printer_t *p)           /* I - Printer */
 {
-  int          i, j, k;                /* Looping vars */
+  int          i, j;                   /* Looping vars */
   char         cache_name[1024];       /* Cache filename */
   struct stat  cache_info;             /* Cache file info */
   ppd_file_t   *ppd;                   /* PPD file */
   char         ppd_name[1024];         /* PPD filename */
   struct stat  ppd_info;               /* PPD file info */
-  int          num_media;              /* Number of media options */
+  char         strings_name[1024];     /* Strings filename */
+  int          num_media;              /* Number of media values */
   ppd_size_t   *size;                  /* Current PPD size */
   ppd_option_t *duplex,                /* Duplex option */
                *output_bin,            /* OutputBin option */
                *output_mode,           /* OutputMode option */
                *resolution;            /* (Set|JCL|)Resolution option */
-  ppd_choice_t *choice,                /* Current PPD choice */
-               *input_slot,            /* Current input slot */
-               *media_type;            /* Current media type */
+  ppd_choice_t *choice;                /* Current PPD choice */
   ppd_attr_t   *ppd_attr;              /* PPD attribute */
   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 */
   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 */
                *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",
@@ -3813,6 +3908,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;
 
@@ -3984,16 +4081,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");
@@ -4023,20 +4128,8 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
       {
         ipp_t  *col;                   /* Collection value */
 
-       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);
+       col = new_media_col(pwgsize);
+       ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-default", col);
         ippDelete(col);
       }
 
@@ -4230,89 +4323,19 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
       * media-col-database
       */
 
-      num_media = p->pc->num_sizes;
-      if (p->pc->num_sources)
+      if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-database", p->pc->num_sizes, NULL)) != NULL)
       {
-        if (p->pc->num_types > 0)
-         num_media += p->pc->num_sizes * p->pc->num_sources *
-                      p->pc->num_types;
-       else
-          num_media += p->pc->num_sizes * p->pc->num_sources;
-      }
-      else if (p->pc->num_types)
-        num_media += p->pc->num_sizes * p->pc->num_types;
+       /*
+       * Add each page size without source or type...
+       */
 
-      if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER,
-                                    "media-col-database", num_media,
-                                   NULL)) != NULL)
-      {
-        for (i = p->pc->num_sizes, pwgsize = p->pc->sizes, val = attr->values;
-            i > 0;
-            i --, pwgsize ++)
+        for (i = 0, pwgsize = p->pc->sizes; i < p->pc->num_sizes; i ++, pwgsize ++)
        {
-        /*
-         * Start by adding the page size without source or type...
-         */
-
-         ppdMarkOption(ppd, "PageSize", pwgsize->map.ppd);
-
-          val->collection = new_media_col(pwgsize, NULL, NULL);
-         val ++;
-
-         /*
-         * Then add the specific, supported combinations of size, source, and
-         * type...
-         */
+         ipp_t *col = new_media_col(pwgsize);
 
-         if (p->pc->num_sources > 0)
-         {
-           for (j = p->pc->num_sources, pwgsource = p->pc->sources;
-                j > 0;
-                j --, pwgsource ++)
-           {
-             ppdMarkOption(ppd, "InputSlot", pwgsource->ppd);
-
-             if (p->pc->num_types > 0)
-             {
-               for (k = p->pc->num_types, pwgtype = p->pc->types;
-                    k > 0;
-                    k --, pwgtype ++)
-               {
-                 if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd))
-                 {
-                   val->collection = new_media_col(pwgsize, pwgsource->pwg,
-                                                   pwgtype->pwg);
-                   val ++;
-                 }
-               }
-             }
-             else if (!ppdConflicts(ppd))
-             {
-               val->collection = new_media_col(pwgsize, pwgsource->pwg, NULL);
-               val ++;
-             }
-           }
-         }
-         else if (p->pc->num_types > 0)
-         {
-           for (j = p->pc->num_types, pwgtype = p->pc->types;
-                j > 0;
-                j --, pwgtype ++)
-           {
-             if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd))
-             {
-               val->collection = new_media_col(pwgsize, NULL, pwgtype->pwg);
-               val ++;
-             }
-           }
-         }
+         ippSetCollection(p->ppd_attrs, &attr, i, col);
+         ippDelete(col);
        }
-
-       /*
-        * Update the number of media-col-database values...
-       */
-
-       attr->num_values = val - attr->values;
       }
     }
 
@@ -4391,6 +4414,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
                     "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
     {
@@ -4398,6 +4422,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
                    "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);
     }
 
    /*
@@ -4435,10 +4460,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;
@@ -4461,9 +4483,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 &&
@@ -4496,6 +4519,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
     {
@@ -4509,6 +4533,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);
     }
 
    /*
@@ -4528,6 +4553,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);
 
@@ -4552,16 +4579,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 ++)
@@ -4874,32 +4975,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) ||
-               !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")))
+    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.
@@ -4907,31 +4989,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...
       */
@@ -4992,9 +5049,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 */
-              const char  *source,     /* I - media-source value */
-              const char  *type)       /* I - media-type value */
+new_media_col(pwg_size_t *size)                /* I - media-size/margin values */
 {
   ipp_t        *media_col,                     /* Collection value */
        *media_size;                    /* media-size value */
@@ -5003,29 +5058,15 @@ new_media_col(_pwg_size_t *size,        /* I - media-size/margin values */
   media_col = ippNew();
 
   media_size = ippNew();
-  ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-               "x-dimension", size->width);
-  ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-               "y-dimension", size->length);
+  ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "x-dimension", size->width);
+  ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "y-dimension", size->length);
   ippAddCollection(media_col, IPP_TAG_PRINTER, "media-size", media_size);
   ippDelete(media_size);
 
-  ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-               "media-bottom-margin", size->bottom);
-  ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-               "media-left-margin", size->left);
-  ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-               "media-right-margin", size->right);
-  ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-               "media-top-margin", size->top);
-
-  if (source)
-    ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-source",
-                NULL, source);
-
-  if (type)
-    ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-type",
-                NULL, type);
+  ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-bottom-margin", size->bottom);
+  ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-left-margin", size->left);
+  ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-right-margin", size->right);
+  ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-top-margin", size->top);
 
   return (media_col);
 }
@@ -5068,8 +5109,3 @@ write_xml_string(cups_file_t *fp, /* I - File to write to */
   if (s > start)
     cupsFilePuts(fp, start);
 }
-
-
-/*
- * End of "$Id$".
- */