]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - scheduler/printers.c
Merge changes from CUPS 1.5svn-r9313.
[thirdparty/cups.git] / scheduler / printers.c
index 3a02ab6294b3c2d9773508db22a7d458afd455e4..537d6e4f4121d8fa7ed19d25f0ea0b57162ea484 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * "$Id: printers.c 7968 2008-09-19 23:03:01Z mike $"
  *
- *   Printer routines for the Common UNIX Printing System (CUPS).
+ *   Printer routines for the CUPS scheduler.
  *
  *   Copyright 2007-2010 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
@@ -51,6 +51,7 @@
  *   delete_string_array()      - Delete an array of CUPS strings.
  *   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
 
 #include "cupsd.h"
 #include <cups/dir.h>
-#include <cups/pwgmedia.h>
+#ifdef HAVE_APPLICATIONSERVICES_H
+#  include <ApplicationServices/ApplicationServices.h>
+#endif /* HAVE_APPLICATIONSERVICES_H */
+#ifdef HAVE_SYS_MOUNT_H
+#  include <sys/mount.h>
+#endif /* HAVE_SYS_MOUNT_H */
+#ifdef HAVE_SYS_STATFS_H
+#  include <sys/statfs.h>
+#endif /* HAVE_SYS_STATFS_H */
+#ifdef HAVE_SYS_STATVFS_H
+#  include <sys/statvfs.h>
+#endif /* HAVE_SYS_STATVFS_H */
+#ifdef HAVE_SYS_VFS_H
+#  include <sys/vfs.h>
+#endif /* HAVE_SYS_VFS_H */
 
 
 /*
@@ -80,6 +95,8 @@ static int    compare_printers(void *first, void *second, void *data);
 static void    delete_printer_filters(cupsd_printer_t *p);
 static void    delete_string_array(cups_array_t **a);
 static void    load_ppd(cupsd_printer_t *p);
+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);
@@ -95,6 +112,7 @@ cupsd_printer_t *                    /* O - New printer */
 cupsdAddPrinter(const char *name)      /* I - Name of printer */
 {
   cupsd_printer_t      *p;             /* New printer */
+  char                 uri[1024];      /* Printer URI */
 
 
  /*
@@ -118,8 +136,9 @@ cupsdAddPrinter(const char *name)   /* I - Name of printer */
   cupsdSetString(&p->info, name);
   cupsdSetString(&p->hostname, ServerName);
 
-  cupsdSetStringf(&p->uri, "ipp://%s:%d/printers/%s", ServerName, RemotePort,
-                  name);
+  httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
+                  ServerName, RemotePort, "/printers/%s", name);
+  cupsdSetString(&p->uri, uri);
   cupsdSetDeviceURI(p, "file:///dev/null");
 
   p->state      = IPP_PRINTER_STOPPED;
@@ -268,6 +287,14 @@ cupsdCreateCommonData(void)
   char                 filename[1024], /* Filename */
                        *notifier;      /* Current notifier */
   cupsd_policy_t       *p;             /* Current policy */
+  int                  k_supported;    /* Maximum file size supported */
+#ifdef HAVE_STATFS
+  struct statfs                spoolinfo;      /* FS info for spool directory */
+  double               spoolsize;      /* FS size */
+#elif defined(HAVE_STATVFS)
+  struct statvfs       spoolinfo;      /* FS info for spool directory */
+  double               spoolsize;      /* FS size */
+#endif /* HAVE_STATFS */
   static const int nups[] =            /* number-up-supported values */
                { 1, 2, 4, 6, 9, 16 };
   static const int orients[4] =/* orientation-requested-supported values */
@@ -307,6 +334,7 @@ cupsdCreateCommonData(void)
                  IPP_GET_PRINTER_ATTRIBUTES,
                  IPP_HOLD_JOB,
                  IPP_RELEASE_JOB,
+                 IPP_RESTART_JOB,
                  IPP_PAUSE_PRINTER,
                  IPP_RESUME_PRINTER,
                  IPP_PURGE_JOBS,
@@ -324,6 +352,9 @@ cupsdCreateCommonData(void)
                  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,
@@ -356,9 +387,12 @@ cupsdCreateCommonData(void)
                };
   static const char * const media_col_supported[] =
                {                       /* media-col-supported values */
-                 "media-color",
-                 "media-key",
+                 "media-bottom-margin",
+                 "media-left-margin",
+                 "media-right-margin",
                  "media-size",
+                 "media-source",
+                 "media-top-margin",
                  "media-type"
                };
   static const char * const multiple_document_handling[] =
@@ -396,15 +430,40 @@ cupsdCreateCommonData(void)
                  "server-started",
                  "server-stopped"
                };
+  static const char * const job_creation[] =
+               {                       /* job-creation-attributes-supported */
+                 "copies",
+                 "finishings",
+                 "ipp-attribute-fidelity",
+                 "job-hold-until",
+                 "job-name",
+                 "job-priority",
+                 "job-sheets",
+                 "media",
+                 "media-col",
+                 "multiple-document-handling",
+                 "number-up",
+                 "output-bin",
+                 "output-mode",
+                 "orientation-requested",
+                 "page-ranges",
+                 "print-quality",
+                 "printer-resolution",
+                 "sides"
+               };
   static const char * const job_settable[] =
                {                       /* job-settable-attributes-supported */
                  "copies",
                  "finishings",
                  "job-hold-until",
+                 "job-name",
                  "job-priority",
                  "media",
+                 "media-col",
                  "multiple-document-handling",
                  "number-up",
+                 "output-bin",
+                 "output-mode",
                  "orientation-requested",
                  "page-ranges",
                  "print-quality",
@@ -416,6 +475,18 @@ cupsdCreateCommonData(void)
                  "printer-info",
                  "printer-location"
                };
+  static const char * const which_jobs[] =
+               {                       /* which-jobs-supported values */
+                 "completed",
+                 "not-completed",
+                 "aborted",
+                 "all",
+                 "canceled",
+                 "pending",
+                 "pending-held",
+                 "processing",
+                 "processing-stopped"
+               };
 
 
   if (CommonData)
@@ -423,6 +494,34 @@ cupsdCreateCommonData(void)
 
   CommonData = ippNew();
 
+ /*
+  * Get the maximum spool size based on the size of the filesystem used for
+  * the RequestRoot directory.  If the host OS doesn't support the statfs call
+  * or the filesystem is larger than 2TiB, always report INT_MAX.
+  */
+
+#ifdef HAVE_STATFS
+  if (statfs(RequestRoot, &spoolinfo))
+    k_supported = INT_MAX;
+  else if ((spoolsize = (double)spoolinfo.f_bsize * spoolinfo.f_blocks / 1024) >
+               INT_MAX)
+    k_supported = INT_MAX;
+  else
+    k_supported = (int)spoolsize;
+
+#elif defined(HAVE_STATVFS)
+  if (statvfs(RequestRoot, &spoolinfo))
+    k_supported = INT_MAX;
+  else if ((spoolsize = (double)spoolinfo.f_frsize * spoolinfo.f_blocks / 1024) >
+               INT_MAX)
+    k_supported = INT_MAX;
+  else
+    k_supported = (int)spoolsize;
+
+#else
+  k_supported = INT_MAX;
+#endif /* HAVE_STATFS */
+
  /*
   * This list of attributes is sorted to improve performance when the
   * client provides a requested-attributes attribute...
@@ -459,11 +558,28 @@ cupsdCreateCommonData(void)
                 "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]),
                NULL, versions);
 
+  /* ippget-event-life */
+  ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                "ippget-event-life", 15);
+
+  /* job-creation-attributes-supported */
+  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+                "job-creation-attributes-supported",
+               sizeof(job_creation) / sizeof(job_creation[0]),
+               NULL, job_creation);
+
   /* job-hold-until-supported */
   ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
                 "job-hold-until-supported", sizeof(holds) / sizeof(holds[0]),
                NULL, holds);
 
+  /* job-ids-supported */
+  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);
+
   /* job-priority-supported */
   ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
                 "job-priority-supported", 100);
@@ -606,9 +722,9 @@ cupsdCreateCommonData(void)
   /* page-ranges-supported */
   ippAddBoolean(CommonData, IPP_TAG_PRINTER, "page-ranges-supported", 1);
 
-  /* pdf-override-supported */
+  /* pdl-override-supported */
   ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
-               "pdl-override-supported", NULL, "not-attempted");
+               "pdl-override-supported", NULL, "attempted");
 
   /* printer-op-policy-supported */
   attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME | IPP_TAG_COPY,
@@ -628,6 +744,11 @@ cupsdCreateCommonData(void)
   /* server-is-sharing-printers */
   ippAddBoolean(CommonData, IPP_TAG_PRINTER, "server-is-sharing-printers",
                 BrowseLocalProtocols != 0 && Browsing);
+
+  /* which-jobs-supported */
+  ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD | IPP_TAG_COPY,
+                "which-jobs-supported",
+                sizeof(which_jobs) / sizeof(which_jobs[0]), NULL, which_jobs);
 }
 
 
@@ -1502,7 +1623,7 @@ cupsdSaveAllPrinters(void)
   */
 
   fchown(cupsFileNumber(fp), getuid(), Group);
-  fchmod(cupsFileNumber(fp), 0600);
+  fchmod(cupsFileNumber(fp), ConfigFilePerm & 0600);
 
  /*
   * Write a small header to the file...
@@ -2621,8 +2742,8 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
 
 int                                    /* O - 1 if something changed, 0 otherwise */
 cupsdSetPrinterReasons(
-    cupsd_printer_t  *p,               /* I - Printer */
-    const char *s)                     /* I - Reasons strings */
+    cupsd_printer_t *p,                        /* I - Printer */
+    const char      *s)                        /* I - Reasons strings */
 {
   int          i,                      /* Looping var */
                changed = 0;            /* Did something change? */
@@ -3431,11 +3552,10 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */
     cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-hold-until-default"));
     cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-priority-default"));
     cupsArrayAdd(CommonDefaults, _cupsStrAlloc("job-sheets-default"));
-    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("media-default"));
+    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("media-col-default"));
     cupsArrayAdd(CommonDefaults, _cupsStrAlloc("number-up-default"));
     cupsArrayAdd(CommonDefaults,
                  _cupsStrAlloc("orientation-requested-default"));
-    cupsArrayAdd(CommonDefaults, _cupsStrAlloc("sides-default"));
   }
 
  /*
@@ -3489,10 +3609,6 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */
     ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
                   "number-up-default", 1);
 
-  if (!cupsGetOption("orientation-requested", p->num_options, p->options))
-    ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE,
-                 "orientation-requested-default", NULL, NULL);
-
   if (!cupsGetOption("notify-lease-duration", p->num_options, p->options))
     ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
                  "notify-lease-duration-default", DefaultLeaseDuration);
@@ -3500,6 +3616,14 @@ add_printer_defaults(cupsd_printer_t *p)/* I - Printer */
   if (!cupsGetOption("notify-events", p->num_options, p->options))
     ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
                 "notify-events-default", NULL, "job-completed");
+
+  if (!cupsGetOption("orientation-requested", p->num_options, p->options))
+    ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_NOVALUE,
+                 "orientation-requested-default", NULL, NULL);
+
+  if (!cupsGetOption("print-quality", p->num_options, p->options))
+    ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+                  "print-quality-default", IPP_QUALITY_NORMAL);
 }
 
 
@@ -3568,12 +3692,11 @@ add_printer_filter(
     if (!RunUser)
     {
      /*
-      * Only use filters that are owned by root and do not have group or world
-      * write permissions.
+      * Only use filters that are owned by root and do not have world write
+      * permissions.
       */
 
-      if (fileinfo.st_uid ||
-          (fileinfo.st_mode & (S_ISUID | S_IWGRP | S_IWOTH)) != 0)
+      if (fileinfo.st_uid || (fileinfo.st_mode & (S_ISUID | S_IWOTH)) != 0)
       {
        if (fileinfo.st_uid)
          snprintf(p->state_message, sizeof(p->state_message),
@@ -3600,7 +3723,7 @@ add_printer_filter(
 
        if (!stat(filename, &fileinfo) &&
            (fileinfo.st_uid ||
-            (fileinfo.st_mode & (S_ISUID | S_IWGRP | S_IWOTH)) != 0))
+            (fileinfo.st_mode & (S_ISUID | S_IWOTH)) != 0))
        {
          if (fileinfo.st_uid)
            snprintf(p->state_message, sizeof(p->state_message),
@@ -3738,19 +3861,9 @@ add_printer_formats(cupsd_printer_t *p)  /* I - Printer */
     mime_filter_t      *filter;        /* MIME filter looping var */
 
 
-    pdl[0] = '\0';
-
-    if (mimeType(MimeDatabase, "application", "pdf"))
-      strlcat(pdl, "application/pdf,", sizeof(pdl));
-
-    if (mimeType(MimeDatabase, "application", "postscript"))
-      strlcat(pdl, "application/postscript,", sizeof(pdl));
-
-    if (mimeType(MimeDatabase, "application", "vnd.cups-raster"))
-      strlcat(pdl, "application/vnd.cups-raster,", sizeof(pdl));
-
    /*
-    * Determine if this is a Tioga PrintJobMgr based queue...
+    * We only support raw printing if this is not a Tioga PrintJobMgr based
+    * queue and if application/octet-stream is a known type...
     */
 
     for (filter = (mime_filter_t *)cupsArrayFirst(MimeDatabase->filters);
@@ -3762,16 +3875,34 @@ add_printer_formats(cupsd_printer_t *p) /* I - Printer */
        break;
     }
 
-   /*
-    * We only support raw printing if this is not a Tioga PrintJobMgr based
-    * queue and if application/octet-stream is a known conversion...
-    */
+    pdl[0] = '\0';
 
     if (!filter && mimeType(MimeDatabase, "application", "octet-stream"))
       strlcat(pdl, "application/octet-stream,", sizeof(pdl));
 
-    if (mimeType(MimeDatabase, "image", "png"))
-      strlcat(pdl, "image/png,", sizeof(pdl));
+   /*
+    * Then list a bunch of formats that are supported by the printer...
+    */
+
+    for (type = (mime_type_t *)cupsArrayFirst(p->filetypes);
+        type;
+        type = (mime_type_t *)cupsArrayNext(p->filetypes))
+    {
+      if (!strcasecmp(type->super, "application"))
+      {
+        if (!strcasecmp(type->type, "pdf"))
+         strlcat(pdl, "application/pdf,", sizeof(pdl));
+        else if (!strcasecmp(type->type, "postscript"))
+         strlcat(pdl, "application/postscript,", sizeof(pdl));
+      }
+      else if (!strcasecmp(type->super, "image"))
+      {
+        if (!strcasecmp(type->type, "jpeg"))
+         strlcat(pdl, "image/jpeg,", sizeof(pdl));
+       else if (!strcasecmp(type->type, "png"))
+         strlcat(pdl, "image/png,", sizeof(pdl));
+      }
+    }
 
     if (pdl[0])
       pdl[strlen(pdl) - 1] = '\0';     /* Remove trailing comma */
@@ -3878,32 +4009,39 @@ delete_string_array(cups_array_t **a)   /* I - Array */
 static void
 load_ppd(cupsd_printer_t *p)           /* I - Printer */
 {
-  int          i;                      /* Looping var */
-  cups_file_t  *cache;                 /* Cache file */
-  char         cache_name[1024];       /* Cache filename */
-  struct stat  cache_info;             /* Cache file info */
+  int          i, j, k;                /* Looping vars */
+  cups_file_t  *cache;                 /* IPP cache file */
+  char         cache_name[1024];       /* IPP cache filename */
+  struct stat  cache_info;             /* IPP cache file info */
+  char         pwg_name[1024];         /* PWG cache filename */
+  struct stat  pwg_info;               /* PWG cache file info */
   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         custom_in[256],         /* Custom size name in inches */
-               custom_mm[256];         /* Custom size name in millimeters */
-  ppd_size_t   *size;                  /* Current size */
+  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 */
+  ppd_choice_t *choice,                /* Current PPD choice */
+               *input_slot,            /* Current input slot */
+               *media_type;            /* Current media type */
   ppd_attr_t   *ppd_attr;              /* PPD attribute */
   int          xdpi,                   /* Horizontal resolution */
                ydpi;                   /* Vertical resolution */
   const char   *resptr;                /* Pointer into resolution keyword */
-  _cups_pwg_media_t *pwgmedia;         /* Matching PWG size name */
+  _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_t                *media_col_default,     /* media-col-default collection value */
-               *media_size;            /* media-size collection value */
   ipp_value_t  *val;                   /* Attribute value */
-  int          num_finishings;         /* Number of finishings */
-  int          finishings[5];          /* finishings-supported values */
+  int          num_finishings,         /* Number of finishings */
+               finishings[5];          /* finishings-supported values */
+  int          num_qualities,          /* Number of print-quality values */
+               qualities[3];           /* print-quality values */
+  int          num_margins,            /* Number of media-*-margin-supported values */
+               margins[16];            /* media-*-margin-supported values */
   static const char * const sides[3] = /* sides-supported values */
                {
                  "one-sided",
@@ -3922,10 +4060,14 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
   * Check to see if the cache is up-to-date...
   */
 
-  snprintf(cache_name, sizeof(cache_name), "%s/%s.ipp", CacheDir, p->name);
+  snprintf(cache_name, sizeof(cache_name), "%s/%s.ipp4", CacheDir, p->name);
   if (stat(cache_name, &cache_info))
     cache_info.st_mtime = 0;
 
+  snprintf(pwg_name, sizeof(pwg_name), "%s/%s.pwg3", CacheDir, p->name);
+  if (stat(pwg_name, &pwg_info))
+    pwg_info.st_mtime = 0;
+
   snprintf(ppd_name, sizeof(ppd_name), "%s/ppd/%s.ppd", ServerRoot, p->name);
   if (stat(ppd_name, &ppd_info))
     ppd_info.st_mtime = 1;
@@ -3933,7 +4075,13 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
   ippDelete(p->ppd_attrs);
   p->ppd_attrs = ippNew();
 
-  if (cache_info.st_mtime >= ppd_info.st_mtime &&
+  _pwgDestroy(p->pwg);
+  p->pwg = NULL;
+
+  if (pwg_info.st_mtime >= ppd_info.st_mtime)
+    p->pwg = _pwgCreateWithFile(pwg_name);
+
+  if (cache_info.st_mtime >= ppd_info.st_mtime && p->pwg &&
       (cache = cupsFileOpen(cache_name, "r")) != NULL)
   {
    /*
@@ -3958,6 +4106,9 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
 
   cupsdMarkDirty(CUPSD_DIRTY_PRINTERS);
 
+  _pwgDestroy(p->pwg);
+  p->pwg = NULL;
+
   cupsdLogMessage(CUPSD_LOG_DEBUG, "load_ppd: Loading %s...", ppd_name);
 
   delete_string_array(&(p->filters));
@@ -3975,6 +4126,8 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
     * Add make/model and other various attributes...
     */
 
+    p->pwg = _pwgCreateWithPPD(ppd);
+
     ppdMarkDefaults(ppd);
 
     if (ppd->color_device)
@@ -3990,8 +4143,51 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
     ippAddBoolean(p->ppd_attrs, IPP_TAG_PRINTER, "color-supported",
                  ppd->color_device);
     if (ppd->throughput)
+    {
       ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
                    "pages-per-minute", ppd->throughput);
+      if (ppd->color_device)
+       ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                     "pages-per-minute-color", ppd->throughput);
+    }
+
+    num_qualities = 0;
+
+    if ((output_mode = ppdFindOption(ppd, "OutputMode")) != NULL)
+    {
+      if (ppdFindChoice(output_mode, "draft") ||
+          ppdFindChoice(output_mode, "fast"))
+        qualities[num_qualities ++] = IPP_QUALITY_DRAFT;
+      if (ppdFindChoice(output_mode, "normal") ||
+          ppdFindChoice(output_mode, "good"))
+        qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
+      if (ppdFindChoice(output_mode, "best") ||
+          ppdFindChoice(output_mode, "high"))
+        qualities[num_qualities ++] = IPP_QUALITY_HIGH;
+    }
+    else if ((ppd_attr = ppdFindAttr(ppd, "APPrinterPreset", NULL)) != NULL)
+    {
+      do
+      {
+        if (strstr(ppd_attr->spec, "draft") ||
+           strstr(ppd_attr->spec, "Draft"))
+       {
+         qualities[num_qualities ++] = IPP_QUALITY_DRAFT;
+         break;
+       }
+      }
+      while ((ppd_attr = ppdFindNextAttr(ppd, "APPrinterPreset",
+                                         NULL)) != NULL);
+
+      qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
+      qualities[num_qualities ++] = IPP_QUALITY_HIGH;
+    }
+
+    if (num_qualities == 0)
+      qualities[num_qualities ++] = IPP_QUALITY_NORMAL;
+
+    ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
+                   "print-quality-supported", num_qualities, qualities);
 
     if (ppd->nickname)
     {
@@ -4022,112 +4218,296 @@ load_ppd(cupsd_printer_t *p)          /* I - Printer */
     * Add media options from the PPD file...
     */
 
-    if (ppd->num_sizes == 0)
+    if (ppd->num_sizes == 0 || !p->pwg)
     {
       if (!ppdFindAttr(ppd, "APScannerOnly", NULL))
        cupsdLogMessage(CUPSD_LOG_CRIT,
                        "The PPD file for printer %s contains no media "
                        "options and is therefore invalid!", p->name);
 
+      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                  "media-default", NULL, "unknown");
       ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
                   "media-supported", NULL, "unknown");
     }
     else
     {
-      num_media = ppd->num_sizes;
-      if (ppd->variable_sizes)
-       num_media ++;
+     /*
+      * media-default
+      */
 
-      attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                          "media-supported", num_media, NULL, NULL);
-      if (attr != NULL)
+      if ((size = ppdPageSize(ppd, NULL)) != NULL)
+        pwgsize = _pwgGetSize(p->pwg, size->name);
+      else
+        pwgsize = NULL;
+
+      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                  "media-default", NULL,
+                  pwgsize ? pwgsize->map.pwg : "unknown");
+
+     /*
+      * media-col-default
+      */
+
+      if (pwgsize)
+      {
+        ipp_t  *col;                   /* Collection value */
+
+       input_slot = ppdFindMarkedChoice(ppd, "InputSlot");
+       media_type = ppdFindMarkedChoice(ppd, "MediaType");
+       col        = new_media_col(pwgsize,
+                                  input_slot ?
+                                      _pwgGetSource(p->pwg,
+                                                    input_slot->choice) :
+                                      NULL,
+                                  media_type ?
+                                      _pwgGetType(p->pwg,
+                                                  media_type->choice) :
+                                      NULL);
+
+       ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-default",
+                        col);
+        ippDelete(col);
+      }
+
+     /*
+      * media-supported
+      */
+
+      num_media = p->pwg->num_sizes;
+      if (p->pwg->custom_min_keyword)
+       num_media += 2;
+
+      if ((attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                               "media-supported", num_media, NULL,
+                               NULL)) != NULL)
       {
        val = attr->values;
 
-        for (i = ppd->num_sizes, size = ppd->sizes; i > 0; i --, size ++)
+        for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes;
+            i > 0;
+            i --, pwgsize ++, val ++)
+         val->string.text = _cupsStrRetain(pwgsize->map.pwg);
+
+        if (p->pwg->custom_min_keyword)
        {
-         if (strcasecmp(size->name, "Custom"))
-         {
-           if ((pwgmedia = _cupsPWGMediaBySize(size->width,
-                                               size->length)) != NULL)
-           {
-             val->string.text = _cupsStrAlloc(pwgmedia->pwg);
-           }
-           else
-           {
-             snprintf(custom_in, sizeof(custom_in), "adobe_%s_%gx%gin",
-                      size->name, size->width / 72.0, size->length / 72.0);
-             snprintf(custom_mm, sizeof(custom_mm), "adobe_%s_%gx%gmm",
-                      size->name, size->width * 25.4 / 72.0,
-                      size->length * 25.4 / 72.0);
-              if (strlen(custom_in) < strlen(custom_mm))
-               val->string.text = _cupsStrAlloc(custom_in);
-             else
-               val->string.text = _cupsStrAlloc(custom_mm);
-           }
+         val->string.text = _cupsStrRetain(p->pwg->custom_min_keyword);
+         val ++;
+         val->string.text = _cupsStrRetain(p->pwg->custom_max_keyword);
+        }
+      }
 
-           if (size->marked)
-           {
-            /*
-             * Add media-default...
-             */
+     /*
+      * media-source-supported
+      */
+
+      if (p->pwg->num_sources > 0 &&
+          (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                               "media-source-supported", p->pwg->num_sources,
+                               NULL, NULL)) != NULL)
+      {
+       for (i = p->pwg->num_sources, pwgsource = p->pwg->sources,
+                val = attr->values;
+            i > 0;
+            i --, pwgsource ++, val ++)
+         val->string.text = _cupsStrRetain(pwgsource->pwg);
+      }
 
-             ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                          "media-default", NULL, val->string.text);
+     /*
+      * media-type-supported
+      */
 
-             /*
-             * Add media-col-default...
-             */
-
-             media_size = ippNew();
-             ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-                           "x-dimension", (int)(size->width * 2540.0 / 72.0));
-             ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
-                           "y-dimension", (int)(size->length * 2540.0 / 72.0));
-
-             media_col_default = ippNew();
-             ippAddString(media_col_default, IPP_TAG_PRINTER,
-                          IPP_TAG_KEYWORD | IPP_TAG_COPY, "media-color", NULL,
-                          "white");
-             ippAddString(media_col_default, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                          "media-key", NULL,val->string.text);
-             ippAddCollection(media_col_default, IPP_TAG_PRINTER, "media-size",
-                              media_size);
-             ippAddString(media_col_default, IPP_TAG_PRINTER,
-                          IPP_TAG_KEYWORD | IPP_TAG_COPY, "media-type", NULL,
-                          "stationary");
-
-              ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER,
-                              "media-col-default", media_col_default);
-           }
+      if (p->pwg->num_types > 0 &&
+          (attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                               "media-type-supported", p->pwg->num_types,
+                               NULL, NULL)) != NULL)
+      {
+       for (i = p->pwg->num_types, pwgtype = p->pwg->types,
+                val = attr->values;
+            i > 0;
+            i --, pwgtype ++, val ++)
+         val->string.text = _cupsStrRetain(pwgtype->pwg);
+      }
 
-            val ++;
-         }
+     /*
+      * media-*-margin-supported
+      */
+
+      for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes, num_margins = 0;
+          i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
+          i --, pwgsize ++)
+      {
+        for (j = 0; j < num_margins; j ++)
+         if (pwgsize->bottom == margins[j])
+           break;
+
+       if (j >= num_margins)
+       {
+         margins[num_margins] = pwgsize->bottom;
+         num_margins ++;
        }
+      }
 
-        if (ppd->variable_sizes)
+      if (num_margins > 0)
+        ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                      "media-bottom-margin-supported", num_margins, margins);
+      else
+        ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                     "media-bottom-margin-supported", 0);
+
+      for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes, num_margins = 0;
+          i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
+          i --, pwgsize ++)
+      {
+        for (j = 0; j < num_margins; j ++)
+         if (pwgsize->left == margins[j])
+           break;
+
+       if (j >= num_margins)
        {
-         snprintf(custom_in, sizeof(custom_in), "custom_min_%gx%gin",
-                  ppd->custom_min[0] / 72.0, ppd->custom_min[1] / 72.0);
-         snprintf(custom_mm, sizeof(custom_mm), "custom_min_%gx%gmm",
-                  ppd->custom_min[0] * 25.4 / 72.0,
-                  ppd->custom_min[1] * 25.4 / 72.0);
-         if (strlen(custom_in) < strlen(custom_mm))
-           val->string.text = _cupsStrAlloc(custom_in);
-         else
-           val->string.text = _cupsStrAlloc(custom_mm);
+         margins[num_margins] = pwgsize->left;
+         num_margins ++;
+       }
+      }
+
+      if (num_margins > 0)
+        ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                      "media-left-margin-supported", num_margins, margins);
+      else
+        ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                     "media-left-margin-supported", 0);
+
+      for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes, num_margins = 0;
+          i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
+          i --, pwgsize ++)
+      {
+        for (j = 0; j < num_margins; j ++)
+         if (pwgsize->right == margins[j])
+           break;
+
+       if (j >= num_margins)
+       {
+         margins[num_margins] = pwgsize->right;
+         num_margins ++;
+       }
+      }
+
+      if (num_margins > 0)
+        ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                      "media-right-margin-supported", num_margins, margins);
+      else
+        ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                     "media-right-margin-supported", 0);
+
+      for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes, num_margins = 0;
+          i > 0 && num_margins < (int)(sizeof(margins) / sizeof(margins[0]));
+          i --, pwgsize ++)
+      {
+        for (j = 0; j < num_margins; j ++)
+         if (pwgsize->top == margins[j])
+           break;
+
+       if (j >= num_margins)
+       {
+         margins[num_margins] = pwgsize->top;
+         num_margins ++;
+       }
+      }
+
+      if (num_margins > 0)
+        ippAddIntegers(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                      "media-top-margin-supported", num_margins, margins);
+      else
+        ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                     "media-top-margin-supported", 0);
+
+     /*
+      * media-col-database
+      */
+
+      num_media = p->pwg->num_sizes;
+      if (p->pwg->num_sources)
+      {
+        if (p->pwg->num_types > 0)
+         num_media += p->pwg->num_sizes * p->pwg->num_sources *
+                      p->pwg->num_types;
+       else
+          num_media += p->pwg->num_sizes * p->pwg->num_sources;
+      }
+      else if (p->pwg->num_types)
+        num_media += p->pwg->num_sizes * p->pwg->num_types;
+
+      if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER,
+                                    "media-col-database", num_media,
+                                   NULL)) != NULL)
+      {
+        for (i = p->pwg->num_sizes, pwgsize = p->pwg->sizes, val = attr->values;
+            i > 0;
+            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 ++;
 
-         snprintf(custom_in, sizeof(custom_in), "custom_max_%gx%gin",
-                  ppd->custom_max[0] / 72.0, ppd->custom_max[1] / 72.0);
-         snprintf(custom_mm, sizeof(custom_mm), "custom_max_%gx%gmm",
-                  ppd->custom_max[0] * 25.4 / 72.0,
-                  ppd->custom_max[1] * 25.4 / 72.0);
-         if (strlen(custom_in) < strlen(custom_mm))
-           val->string.text = _cupsStrAlloc(custom_in);
-         else
-           val->string.text = _cupsStrAlloc(custom_mm);
+         /*
+         * Then add the specific, supported combinations of size, source, and
+         * type...
+         */
+
+         if (p->pwg->num_sources > 0)
+         {
+           for (j = p->pwg->num_sources, pwgsource = p->pwg->sources;
+                j > 0;
+                j --, pwgsource ++)
+           {
+             ppdMarkOption(ppd, "InputSlot", pwgsource->ppd);
+
+             if (p->pwg->num_types > 0)
+             {
+               for (k = p->pwg->num_types, pwgtype = p->pwg->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->pwg->num_types > 0)
+         {
+           for (j = p->pwg->num_types, pwgtype = p->pwg->types;
+                j > 0;
+                j --, pwgtype ++)
+           {
+             if (!ppdMarkOption(ppd, "MediaType", pwgtype->ppd))
+             {
+               val->collection = new_media_col(pwgsize, NULL, pwgtype->pwg);
+               val ++;
+             }
+           }
+         }
        }
+
+       /*
+        * Update the number of media-col-database values...
+       */
+
+       attr->num_values = val - attr->values;
       }
     }
 
@@ -4135,22 +4515,84 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
     * Output bin...
     */
 
-    if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
+    if (p->pwg && p->pwg->num_bins > 0)
     {
       attr = ippAddStrings(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                          "output-bin-supported", output_bin->num_choices,
+                          "output-bin-supported", p->pwg->num_bins,
                           NULL, NULL);
 
       if (attr != NULL)
       {
        for (i = 0, val = attr->values;
-            i < output_bin->num_choices;
+            i < p->pwg->num_bins;
             i ++, val ++)
-         val->string.text = _cupsStrAlloc(output_bin->choices[i].choice);
+         val->string.text = _cupsStrAlloc(p->pwg->bins[i].pwg);
+      }
+
+      if ((output_bin = ppdFindOption(ppd, "OutputBin")) != NULL)
+      {
+       for (i = 0; i < p->pwg->num_bins; i ++)
+         if (!strcmp(p->pwg->bins[i].ppd, output_bin->defchoice))
+           break;
+
+        if (i >= p->pwg->num_bins)
+         i = 0;
+
+       ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                    "output-bin-default", NULL, p->pwg->bins[i].pwg);
       }
+      else
+        ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                    "output-bin-default", NULL, p->pwg->bins[0].pwg);
+    }
+    else if (((ppd_attr = ppdFindAttr(ppd, "DefaultOutputOrder",
+                                     NULL)) != NULL &&
+             !strcasecmp(ppd_attr->value, "Reverse")) ||
+            (!ppd_attr && ppd->manufacturer && /* "Compatibility heuristic" */
+             (!strcasecmp(ppd->manufacturer, "epson") ||
+              !strcasecmp(ppd->manufacturer, "lexmark"))))
+    {
+     /*
+      * Report that this printer has a single output bin that leaves pages face
+      * up.
+      */
 
       ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
-                  "output-bin-default", NULL, output_bin->defchoice);
+                  "output-bin-supported", NULL, "face-up");
+      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                  "output-bin-default", NULL, "face-up");
+    }
+    else
+    {
+      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                  "output-bin-supported", NULL, "face-down");
+      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                  "output-bin-default", NULL, "face-down");
+    }
+
+   /*
+    * output-mode...
+    */
+
+    if (ppd->color_device)
+    {
+      static const char * const output_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");
+    }
+    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");
     }
 
    /*
@@ -4177,25 +4619,20 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
            i < resolution->num_choices;
           i ++, choice ++)
       {
-        xdpi = (int)strtol(choice->choice, (char **)&resptr, 10);
-       if (resptr > choice->choice && xdpi > 0)
-       {
-         if (*resptr == 'x')
-           ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10);
-         else
-           ydpi = xdpi;
-        }
+        xdpi = ydpi = (int)strtol(choice->choice, (char **)&resptr, 10);
+       if (resptr > choice->choice && xdpi > 0 && *resptr == 'x')
+         ydpi = (int)strtol(resptr + 1, (char **)&resptr, 10);
 
        if (xdpi <= 0 || ydpi <= 0)
        {
          cupsdLogMessage(CUPSD_LOG_WARN,
                          "Bad resolution \"%s\" for printer %s.",
                          choice->choice, p->name);
-         xdpi = ydpi = 72;
+         xdpi = ydpi = 300;
        }
 
         attr->values[i].resolution.xres  = xdpi;
-        attr->values[i].resolution.yres  = xdpi;
+        attr->values[i].resolution.yres  = ydpi;
         attr->values[i].resolution.units = IPP_RES_PER_INCH;
 
         if (choice->marked)
@@ -4211,7 +4648,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
       * Just the DefaultResolution to report...
       */
 
-      xdpi = (int)strtol(ppd_attr->value, (char **)&resptr, 10);
+      xdpi = ydpi = (int)strtol(ppd_attr->value, (char **)&resptr, 10);
       if (resptr > ppd_attr->value && xdpi > 0)
       {
        if (*resptr == 'x')
@@ -4225,7 +4662,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
        cupsdLogMessage(CUPSD_LOG_WARN,
                        "Bad default resolution \"%s\" for printer %s.",
                        ppd_attr->value, p->name);
-       xdpi = ydpi = 72;
+       xdpi = ydpi = 300;
       }
 
       ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
@@ -4243,16 +4680,18 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
 
       ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
                       "printer-resolution-default", IPP_RES_PER_INCH,
-                      72, 72);
+                      300, 300);
       ippAddResolution(p->ppd_attrs, IPP_TAG_PRINTER,
                       "printer-resolution-supported", IPP_RES_PER_INCH,
-                      72, 72);
+                      300, 300);
     }
 
    /*
     * Duplexing, etc...
     */
 
+    ppdMarkDefaults(ppd);
+
     if ((duplex = ppdFindOption(ppd, "Duplex")) == NULL)
       if ((duplex = ppdFindOption(ppd, "EFDuplex")) == NULL)
        if ((duplex = ppdFindOption(ppd, "EFDuplexing")) == NULL)
@@ -4277,6 +4716,13 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
        ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
                     "sides-default", NULL, "one-sided");
     }
+    else
+    {
+      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                  "sides-supported", NULL, "one-sided");
+      ippAddString(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+                  "sides-default", NULL, "one-sided");
+    }
 
     if (ppdFindOption(ppd, "Collate") != NULL)
       p->type |= CUPS_PRINTER_COLLATE;
@@ -4507,6 +4953,129 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
     if (ppdFindAttr(ppd, "APRemoteQueueID", NULL))
       p->type |= CUPS_PRINTER_REMOTE;
 
+#ifdef HAVE_APPLICATIONSERVICES_H
+   /*
+    * Convert the file referenced in APPrinterIconPath to a 128x128 PNG
+    * and save it as cacheDir/printername.png
+    */
+
+    if ((ppd_attr = ppdFindAttr(ppd, "APPrinterIconPath", NULL)) != NULL &&
+        ppd_attr->value)
+    {
+      CGImageRef       imageRef = NULL;/* Current icon image */
+      CGImageRef       biggestIconRef = NULL;
+                                       /* Biggest icon image */
+      CGImageRef       closestTo128IconRef = NULL;
+                                       /* Icon image closest to and >= 128 */
+      CGImageSourceRef sourceRef;      /* The file's image source */
+      char             outPath[HTTP_MAX_URI];
+                                       /* The path to the PNG file */
+      CFURLRef         outUrl;         /* The URL made from the outPath */
+      CFURLRef         icnsFileUrl;    /* The URL of the original ICNS icon file */
+      CGImageDestinationRef destRef;   /* The image destination to write */
+      size_t           bytesPerRow;    /* The bytes per row used for resizing */
+      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);
+      if (outUrl && icnsFileUrl)
+      {
+        sourceRef = CGImageSourceCreateWithURL(icnsFileUrl, NULL);
+        if (sourceRef)
+        {
+          for (i = 0; i < CGImageSourceGetCount(sourceRef); i ++)
+          {
+            imageRef = CGImageSourceCreateImageAtIndex(sourceRef, i, NULL);
+            if (imageRef &&
+                CGImageGetWidth(imageRef) == CGImageGetHeight(imageRef))
+            {
+             /*
+              * Loop through remembering the icon closest to 128 but >= 128
+              * and then remember the largest icon.
+              */
+
+              if (CGImageGetWidth(imageRef) >= 128 &&
+                 (!closestTo128IconRef ||
+                  CGImageGetWidth(imageRef) <
+                      CGImageGetWidth(closestTo128IconRef)))
+              {
+                CGImageRelease(closestTo128IconRef);
+                CGImageRetain(imageRef);
+                closestTo128IconRef = imageRef;
+              }
+
+              if (!biggestIconRef ||
+                 CGImageGetWidth(imageRef) > CGImageGetWidth(biggestIconRef))
+              {
+                CGImageRelease(biggestIconRef);
+                CGImageRetain(imageRef);
+                biggestIconRef = imageRef;
+              }
+
+              CGImageRelease(imageRef);
+            }
+          }
+
+          if (biggestIconRef)
+          {
+           /*
+            * If biggestIconRef is NULL, we found no icons. Otherwise we first
+            * want the closest to 128, but if none are larger than 128, we want
+            * the largest icon available.
+            */
+
+            imageRef = closestTo128IconRef ? closestTo128IconRef :
+                                             biggestIconRef;
+            CGImageRetain(imageRef);
+            CGImageRelease(biggestIconRef);
+            CGImageRelease(closestTo128IconRef);
+            destRef = CGImageDestinationCreateWithURL(outUrl, kUTTypePNG, 1,
+                                                      NULL);
+            if (destRef)
+            {
+              if (CGImageGetWidth(imageRef) != 128)
+              {
+                bytesPerRow = CGImageGetBytesPerRow(imageRef) /
+                              CGImageGetWidth(imageRef) * 128;
+                context     = CGBitmapContextCreate(NULL, 128, 128,
+                                                   CGImageGetBitsPerComponent(imageRef),
+                                                   bytesPerRow,
+                                                   CGImageGetColorSpace(imageRef),
+                                                   kCGImageAlphaPremultipliedFirst);
+                if (context)
+                {
+                  CGContextDrawImage(context, CGRectMake(0, 0, 128, 128),
+                                    imageRef);
+                  CGImageRelease(imageRef);
+                  imageRef = CGBitmapContextCreateImage(context);
+                  CGContextRelease(context);
+                }
+              }
+
+              CGImageDestinationAddImage(destRef, imageRef, NULL);
+              CGImageDestinationFinalize(destRef);
+              CFRelease(destRef);
+            }
+
+            CGImageRelease(imageRef);
+          }
+
+          CFRelease(sourceRef);
+          CFRelease(icnsFileUrl);
+        }
+
+        CFRelease(outUrl);
+      }
+    }
+#endif /* HAVE_APPLICATIONSERVICES_H */
+
    /*
     * Close the PPD and set the type...
     */
@@ -4626,7 +5195,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
   ippAddInteger(p->ppd_attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
                "finishings-default", IPP_FINISHINGS_NONE);
 
-  if (ppd && (cache = cupsFileOpen(cache_name, "w")) != NULL)
+  if (ppd && (cache = cupsFileOpen(cache_name, "w9")) != NULL)
   {
    /*
     * Save cached PPD attributes to disk...
@@ -4646,18 +5215,68 @@ load_ppd(cupsd_printer_t *p)            /* I - Printer */
     }
 
     cupsFileClose(cache);
+
+    _pwgWriteFile(p->pwg, pwg_name);
   }
-  else if (cache_info.st_mtime)
+  else
   {
    /*
-    * Remove cache file...
+    * Remove cache files...
     */
 
-    unlink(cache_name);
+    if (cache_info.st_mtime)
+      unlink(cache_name);
+
+    if (pwg_info.st_mtime)
+      unlink(pwg_name);
   }
 }
 
 
+/*
+ * 'new_media_col()' - Create a media-col collection value.
+ */
+
+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 */
+{
+  ipp_t        *media_col,                     /* Collection value */
+       *media_size;                    /* media-size value */
+
+
+  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);
+  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);
+
+  return (media_col);
+}
+
+
 #ifdef __sgi
 /*
  * 'write_irix_config()' - Update the config files used by the IRIX