]> 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 b4c625cd58de86862a92fa6d015a49a080c5cf89..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.
 
 #include "cupsd.h"
 #include <cups/dir.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 */
 
 
 /*
@@ -97,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 */
 
 
  /*
@@ -120,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;
@@ -270,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 */
@@ -309,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,
@@ -408,6 +434,7 @@ cupsdCreateCommonData(void)
                {                       /* job-creation-attributes-supported */
                  "copies",
                  "finishings",
+                 "ipp-attribute-fidelity",
                  "job-hold-until",
                  "job-name",
                  "job-priority",
@@ -417,6 +444,7 @@ cupsdCreateCommonData(void)
                  "multiple-document-handling",
                  "number-up",
                  "output-bin",
+                 "output-mode",
                  "orientation-requested",
                  "page-ranges",
                  "print-quality",
@@ -435,6 +463,7 @@ cupsdCreateCommonData(void)
                  "multiple-document-handling",
                  "number-up",
                  "output-bin",
+                 "output-mode",
                  "orientation-requested",
                  "page-ranges",
                  "print-quality",
@@ -447,17 +476,17 @@ cupsdCreateCommonData(void)
                  "printer-location"
                };
   static const char * const which_jobs[] =
-  {                                    /* which-jobs-supported values */
-    "completed",
-    "not-completed",
-    "aborted",
-    "all",
-    "canceled",
-    "pending",
-    "pending-held",
-    "processing",
-    "processing-stopped"
-  };
+               {                       /* which-jobs-supported values */
+                 "completed",
+                 "not-completed",
+                 "aborted",
+                 "all",
+                 "canceled",
+                 "pending",
+                 "pending-held",
+                 "processing",
+                 "processing-stopped"
+               };
 
 
   if (CommonData)
@@ -465,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...
@@ -501,6 +558,10 @@ 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",
@@ -515,6 +576,10 @@ cupsdCreateCommonData(void)
   /* 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);
@@ -657,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,
@@ -1558,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...
@@ -2677,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? */
@@ -3487,12 +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"));
   }
 
  /*
@@ -3629,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),
@@ -3661,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),
@@ -3998,11 +4060,11 @@ 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.ipp2", 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.pwg", CacheDir, p->name);
+  snprintf(pwg_name, sizeof(pwg_name), "%s/%s.pwg3", CacheDir, p->name);
   if (stat(pwg_name, &pwg_info))
     pwg_info.st_mtime = 0;
 
@@ -4201,7 +4263,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
                                   media_type ?
                                       _pwgGetType(p->pwg,
                                                   media_type->choice) :
-                                  NULL);
+                                      NULL);
 
        ippAddCollection(p->ppd_attrs, IPP_TAG_PRINTER, "media-col-default",
                         col);
@@ -4453,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-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-bin-default", NULL, output_bin->defchoice);
+                   "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");
     }
 
    /*
@@ -4504,7 +4628,7 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
          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;
@@ -4524,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')
@@ -4538,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,
@@ -4556,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)
@@ -4590,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;
@@ -4820,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...
     */