]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Merge changes from CUPS 1.4svn-r7791.
authormsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Thu, 24 Jul 2008 01:02:46 +0000 (01:02 +0000)
committermsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Thu, 24 Jul 2008 01:02:46 +0000 (01:02 +0000)
git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@886 a1ca3aef-8c08-0410-bb20-df032aa958be

20 files changed:
CHANGES-1.3.txt
CHANGES.txt
backend/usb-darwin.c
backend/usb-libusb.c
cups/Dependencies
cups/conflicts.c
cups/emit.c
cups/libcups.exp
cups/page.c
cups/ppd.c
cups/ppd.h
cups/test2.ppd
cups/testppd.c
doc/help/api-ppd.html
scheduler/ipp.c
scheduler/job.c
scheduler/log.c
scheduler/printers.c
systemv/cupstestppd.c
tools/makesrcdist

index 94106486d861122a3ffabced39997af11e1a280b..fca0738fa26c89c989e4a87068c1a2fe079c02ea 100644 (file)
@@ -1,9 +1,18 @@
 CHANGES-1.3.txt
 ---------------
 
+CHANGES IN CUPS V1.3.9
+
+       - ppdEmit*() did not support custom JCL options (STR #2889)
+       - The cupstestppd utility incorrectly reported missing
+         "en" base translations (STR #2887)
+
+
 CHANGES IN CUPS V1.3.8
 
        - Documentation updates (STR #2785, STR #2861, STR #2862)
+       - The scheduler did not add the ending job sheet when the
+         job was released.
        - The IPP backend did not relay marker-* attributes.
        - The CUPS GNOME/KDE menu item was not localized for
          Chinese (STR #2880)
index 083ceae010f91e774f3b3cab639b256454f0a3db..f3f407183e98d663a1d586e83a8245623ddbfae8 100644 (file)
@@ -1,8 +1,12 @@
-CHANGES.txt - 2008-07-18
+CHANGES.txt - 2008-07-23
 ------------------------
 
 CHANGES IN CUPS V1.4b1
 
+       - Added ppdPageSizeLimits API.
+       - Added support for new cupsMediaQualifier2, cupsMediaQualifier3,
+         cupsMinSize, and cupsMaxSize attributes.
+       - Added cupsResolveConflicts and ppdInstallableConflict APIs.
        - Added support for new cupsUIConstraints and cupsUIResolver
          attributes for better option conflict detection and
          resolution.
index 28d45f29ff0456696f2a0a4a94447ac9251b0451..d0371378b163a425f1e6f3ccfad6870a6a9227d4 100644 (file)
@@ -358,9 +358,14 @@ print_device(const char *uri,              /* I - Device URI */
 
   if (!g.make || !g.model)
   {
-    _cupsLangPrintf(stderr, 
-                   _("ERROR: Unable to create make and model strings\n"));
-    return CUPS_BACKEND_STOP;
+    _cupsLangPuts(stderr, _("ERROR: Fatal USB error!\n"));
+
+    if (!g.make)
+      fputs("DEBUG: USB make string is NULL!\n", stderr);
+    if (!g.model)
+      fputs("DEBUG: USB model string is NULL!\n", stderr);
+
+    return (CUPS_BACKEND_STOP);
   }
 
   fputs("STATE: +connecting-to-device\n", stderr);
@@ -410,12 +415,13 @@ print_device(const char *uri,             /* I - Device URI */
         strlcpy(print_buffer, "USB class driver", sizeof(print_buffer));
 
       fputs("STATE: +apple-missing-usbclassdriver-error\n", stderr);
-      _cupsLangPrintf(stderr, _("FATAL: Could not load %s\n"), print_buffer);
+      _cupsLangPuts(stderr, _("ERROR: Fatal USB error!\n"));
+      fprintf(stderr, "DEBUG: Could not load %s\n", print_buffer);
 
       if (driverBundlePath)
        CFRelease(driverBundlePath);
 
-      return CUPS_BACKEND_STOP;
+      return (CUPS_BACKEND_STOP);
     }
 
     if (driverBundlePath)
@@ -427,8 +433,9 @@ print_device(const char *uri,               /* I - Device URI */
       countdown -= PRINTER_POLLING_INTERVAL;
       if (countdown <= 0)
       {
-       _cupsLangPrintf(stderr, _("INFO: Printer busy (status:0x%08x)\n"),
-                       (int)status);
+       _cupsLangPuts(stderr,
+                     _("INFO: Waiting for printer to become available...\n"));
+       fprintf(stderr, "DEBUG: USB printer status: 0x%08x\n", (int)status);
        countdown = SUBSEQUENT_LOG_INTERVAL;    /* subsequent log entries, every 15 seconds */
       }
     }
@@ -473,8 +480,9 @@ print_device(const char *uri,               /* I - Device URI */
 
     if (pthread_create(&sidechannel_thread_id, NULL, sidechannel_thread, NULL))
     {
-      _cupsLangPuts(stderr, _("WARNING: Couldn't create side channel\n"));
-      return CUPS_BACKEND_STOP;
+      _cupsLangPuts(stderr, _("ERROR: Fatal USB error!\n"));
+      fputs("DEBUG: Couldn't create side-channel thread!\n", stderr);
+      return (CUPS_BACKEND_STOP);
     }
   }
 
@@ -490,8 +498,9 @@ print_device(const char *uri,               /* I - Device URI */
 
   if (pthread_create(&read_thread_id, NULL, read_thread, NULL))
   {
-    _cupsLangPuts(stderr, _("WARNING: Couldn't create read channel\n"));
-    return CUPS_BACKEND_STOP;
+    _cupsLangPuts(stderr, _("ERROR: Fatal USB error!\n"));
+    fputs("DEBUG: Couldn't create read thread!\n", stderr);
+    return (CUPS_BACKEND_STOP);
   }
 
  /*
@@ -505,7 +514,7 @@ print_device(const char *uri,               /* I - Device URI */
 
   while (status == noErr && copies-- > 0)
   {
-    _cupsLangPuts(stderr, _("INFO: Sending data\n"));
+    _cupsLangPuts(stderr, _("INFO: Sending print data...\n"));
 
     if (print_fd != STDIN_FILENO)
     {
@@ -573,8 +582,9 @@ print_device(const char *uri,               /* I - Device URI */
        }
        else if (errno != EAGAIN)
        {
-        _cupsLangPrintf(stderr, _("ERROR: select() returned %d\n"), (int)errno);
-        return CUPS_BACKEND_STOP;
+         _cupsLangPuts(stderr, _("ERROR: Unable to read print data!\n"));
+         perror("DEBUG: select");
+         return (CUPS_BACKEND_STOP);
        }
       }
 
@@ -605,7 +615,8 @@ print_device(const char *uri,               /* I - Device URI */
 
          if (errno != EAGAIN || errno != EINTR)
          {
-           _cupsLangPrintError(_("ERROR: Unable to read print data"));
+           _cupsLangPuts(stderr, _("ERROR: Unable to read print data!\n"));
+           perror("DEBUG: read");
            return CUPS_BACKEND_STOP;
          }
 
@@ -649,8 +660,11 @@ print_device(const char *uri,              /* I - Device URI */
          */
 
          OSStatus err = (*g.classdriver)->Abort(g.classdriver);
-         _cupsLangPrintf(stderr, _("ERROR: %ld: (canceled:%ld)\n"),
-                         (long)status, (long)err);
+         _cupsLangPuts(stderr, _("ERROR: Unable to send print data!\n"));
+         fprintf(stderr, "DEBUG: USB class driver WritePipe returned %ld\n",
+                 (long)status);
+         fprintf(stderr, "DEBUG: USB class driver Abort returned %ld\n",
+                 (long)err);
          status = CUPS_BACKEND_STOP;
          break;
        }
@@ -1705,7 +1719,7 @@ static void setup_cfLanguage(void)
     langArray = CFArrayCreate(kCFAllocatorDefault, (const void **)lang, sizeof(lang) / sizeof(lang[0]), &kCFTypeArrayCallBacks);
 
     CFPreferencesSetAppValue(CFSTR("AppleLanguages"), langArray, kCFPreferencesCurrentApplication);
-    fprintf(stderr, "DEBUG: usb: AppleLanguages = \"%s\"\n", requestedLang);
+    fprintf(stderr, "DEBUG: usb: AppleLanguages=\"%s\"\n", requestedLang);
 
     CFRelease(lang[0]);
     CFRelease(langArray);
@@ -1801,7 +1815,8 @@ static void run_ppc_backend(int argc,
 
       execv("/usr/libexec/cups/backend/usb", my_argv);
 
-      _cupsLangPrintError(_("ERROR: Unable to exec /usr/libexec/cups/backend/usb"));
+      _cupsLangPrintf(stderr, _("Unable to use legacy USB class driver!\n"));
+      perror("DEBUG: Unable to exec /usr/libexec/cups/backend/usb");
       exit(errno);
     }
     else if (child_pid < 0)
@@ -1810,7 +1825,8 @@ static void run_ppc_backend(int argc,
       * Error - couldn't fork a new process!
       */
 
-      _cupsLangPrintError(_("ERROR: Unable to fork"));
+      _cupsLangPrintf(stderr, _("Unable to use legacy USB class driver!\n"));
+      perror("DEBUG: Unable to fork");
       exit(errno);
     }
 
@@ -1827,7 +1843,8 @@ static void run_ppc_backend(int argc,
     close(fd);
     close(1);
 
-    fprintf(stderr, "DEBUG: Started usb(ppc) backend (PID %d)\n", (int)child_pid);
+    fprintf(stderr, "DEBUG: Started usb(legacy) backend (PID %d)\n",
+            (int)child_pid);
 
     while ((waitpid_status = waitpid(child_pid, &childstatus, 0)) == (pid_t)-1 && errno == EINTR)
       usleep(1000);
@@ -1835,19 +1852,23 @@ static void run_ppc_backend(int argc,
     if (WIFSIGNALED(childstatus))
     {
       exitstatus = WTERMSIG(childstatus);
-      fprintf(stderr, "DEBUG: usb(ppc) backend %d crashed on signal %d!\n", child_pid, exitstatus);
+      fprintf(stderr, "DEBUG: usb(legacy) backend %d crashed on signal %d!\n",
+              child_pid, exitstatus);
     }
     else
     {
       if ((exitstatus = WEXITSTATUS(childstatus)) != 0)
-       fprintf(stderr, "DEBUG: usb(ppc) backend %d stopped with status %d!\n", child_pid, exitstatus);
+       fprintf(stderr,
+               "DEBUG: usb(legacy) backend %d stopped with status %d!\n",
+               child_pid, exitstatus);
       else
-       fprintf(stderr, "DEBUG: PID %d exited with no errors\n", child_pid);
+       fprintf(stderr, "DEBUG: usb(legacy) backend %d exited with no errors\n",
+               child_pid);
     }
   }
   else
   {
-    fputs("DEBUG: usb child running i386 again\n", stderr);
+    fputs("DEBUG: usb(legacy) backend running native again\n", stderr);
     exitstatus = ENOENT;
   }
 
index a2ec1fa574713258d1db68f9cfee70fb45e66254..4a7716ec30d02de5f049a5914ee136edba43e9d0 100644 (file)
  *
  * Contents:
  *
+ *   list_devices()    - List the available printers.
+ *   print_device()    - Print a file to a USB device.
+ *   close_device()    - Close the connection to the USB printer.
+ *   find_device()     - Find or enumerate USB printers.
+ *   get_device_id()   - Get the IEEE-1284 device ID for the printer.
+ *   list_cb()         - List USB printers for discovery.
+ *   make_device_uri() - Create a device URI for a USB printer.
+ *   open_device()     - Open a connection to the USB printer.
+ *   print_cb()        - Find a USB printer for printing.
+ *   side_cb()         - Handle side-channel requests.
  */
 
 /*
@@ -20,6 +30,7 @@
  */
 
 #include <usb.h>
+#include <poll.h>
 
 
 /*
@@ -57,6 +68,7 @@ static char           *make_device_uri(usb_printer_t *printer,
 static int             open_device(usb_printer_t *printer, int verbose);
 static int             print_cb(usb_printer_t *printer, const char *device_uri,
                                 const char *device_id, const void *data);
+static ssize_t         side_cb(usb_printer_t *printer, int print_fd);
 
 
 /*
@@ -90,8 +102,7 @@ print_device(const char *uri,                /* I - Device URI */
                tbytes;                 /* Total bytes written */
   char         buffer[8192];           /* Print data buffer */
   struct sigaction action;             /* Actions for POSIX signals */
-  int          read_endp,              /* Read endpoint */
-               write_endp;             /* Write endpoint */
+  struct pollfd        pfds[2];                /* Poll descriptors */
 
 
   fputs("DEBUG: print_device\n", stderr);
@@ -107,14 +118,6 @@ print_device(const char *uri,              /* I - Device URI */
     sleep(5);
   }
 
-  read_endp  = printer->device->config[printer->conf].
-                   interface[printer->iface].
-                  altsetting[printer->altset].
-                  endpoint[printer->read_endp].bEndpointAddress;
-  write_endp = printer->device->config[printer->conf].
-                   interface[printer->iface].
-                  altsetting[printer->altset].
-                  endpoint[printer->write_endp].bEndpointAddress;
 
  /*
   * If we are printing data from a print driver on stdin, ignore SIGTERM
@@ -134,6 +137,11 @@ print_device(const char *uri,              /* I - Device URI */
 
   tbytes = 0;
 
+  pfds[0].fd     = print_fd;
+  pfds[0].events = POLLIN;
+  pfds[1].fd     = CUPS_SC_FD;
+  pfds[1].events = POLLIN;
+
   while (copies > 0 && tbytes >= 0)
   {
     copies --;
@@ -145,23 +153,33 @@ print_device(const char *uri,             /* I - Device URI */
     }
 
    /*
-    * TODO: Add side-channel and back-channel support, along with better
-    * error handling for writes.
+    * TODO: Add back-channel support, along with better write error handling.
     */
 
-    while ((bytes = read(print_fd, buffer, sizeof(buffer))) > 0)
+    if (poll(pfds, 2, -1) > 0)
     {
-      while (usb_bulk_write(printer->handle, write_endp, buffer, bytes,
-                            5000) < 0)
+      if (pfds[0].revents & POLLIN)
       {
-        _cupsLangPrintf(stderr,
-                       _("ERROR: Unable to write %d bytes to printer!\n"),
-                       (int)bytes);
-        tbytes = -1;
-       break;
+       if ((bytes = read(print_fd, buffer, sizeof(buffer))) > 0)
+       {
+         while (usb_bulk_write(printer->handle, printer->write_endp, buffer,
+                               bytes, 5000) < 0)
+         {
+           _cupsLangPrintf(stderr,
+                           _("ERROR: Unable to write %d bytes to printer!\n"),
+                           (int)bytes);
+           tbytes = -1;
+           break;
+         }
+
+         tbytes += bytes;
+       }
+       else if (bytes < 0 && errno != EAGAIN && errno != EINTR)
+         break;
       }
 
-      tbytes += bytes;
+      if (pfds[1].revents & POLLIN)
+        tbytes += side_cb(printer, print_fd);
     }
   }
 
@@ -318,7 +336,19 @@ find_device(usb_cb_t   cb,         /* I - Callback function */
                                sizeof(device_uri));
 
                if ((*cb)(&printer, device_uri, device_id, data))
+               {
+                 printer.read_endp  = printer.device->config[printer.conf].
+                                          interface[printer.iface].
+                                          altsetting[printer.altset].
+                                          endpoint[printer.read_endp].
+                                          bEndpointAddress;
+                 printer.write_endp = printer.device->config[printer.conf].
+                                          interface[printer.iface].
+                                          altsetting[printer.altset].
+                                          endpoint[printer.write_endp].
+                                          bEndpointAddress;
                  return (&printer);
+               }
               }
 
               close_device(&printer);
@@ -674,6 +704,97 @@ print_cb(usb_printer_t *printer,   /* I - Printer */
 }
 
 
+/*
+ * 'side_cb()' - Handle side-channel requests.
+ */
+
+static ssize_t                         /* O - Number of bytes written */
+side_cb(usb_printer_t *printer,                /* I - Printer */
+        int           print_fd)                /* I - File to print */
+{
+  ssize_t              bytes,          /* Bytes read/written */
+                       tbytes;         /* Total bytes written */
+  char                 buffer[8192];   /* Print data buffer */
+  struct pollfd                pfd;            /* Poll descriptor */
+  cups_sc_command_t    command;        /* Request command */
+  cups_sc_status_t     status;         /* Request/response status */
+  char                 data[2048];     /* Request/response data */
+  int                  datalen;        /* Request/response data size */
+
+
+  tbytes  = 0;
+  datalen = sizeof(data);
+
+  if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
+  {
+    _cupsLangPuts(stderr, _("WARNING: Failed to read side-channel request!\n"));
+    return (0);
+  }
+
+  switch (command)
+  {
+    case CUPS_SC_CMD_DRAIN_OUTPUT :
+       pfd.fd     = print_fd;
+       pfd.events = POLLIN;
+
+       while (poll(&pfd, 1, 1000) > 0)
+       {
+         if ((bytes = read(print_fd, buffer, sizeof(buffer))) > 0)
+         {
+           while (usb_bulk_write(printer->handle, printer->write_endp, buffer,
+                                 bytes, 5000) < 0)
+           {
+             _cupsLangPrintf(stderr,
+                             _("ERROR: Unable to write %d bytes to printer!\n"),
+                             (int)bytes);
+             tbytes = -1;
+             break;
+           }
+
+           tbytes += bytes;
+         }
+         else if (bytes < 0 && errno != EAGAIN && errno != EINTR)
+           break;
+        }
+
+        if (tbytes < 0)
+         status = CUPS_SC_STATUS_IO_ERROR;
+       else
+         status = CUPS_SC_STATUS_OK;
+
+       datalen = 0;
+        break;
+
+    case CUPS_SC_CMD_GET_BIDI :
+        data[0] = 0;                   /* TODO: Change to 1 when read supported */
+        datalen = 1;
+        break;
+
+    case CUPS_SC_CMD_GET_DEVICE_ID :
+       if (get_device_id(printer, data, sizeof(data)))
+        {
+         status  = CUPS_SC_STATUS_IO_ERROR;
+         datalen = 0;
+       }
+       else
+        {
+         status  = CUPS_SC_STATUS_OK;
+         datalen = strlen(data);
+       }
+        break;
+
+    default :
+        status  = CUPS_SC_STATUS_NOT_IMPLEMENTED;
+       datalen = 0;
+       break;
+  }
+
+  cupsSideChannelWrite(command, status, data, datalen, 1.0);
+
+  return (tbytes);
+}
+
+
 /*
  * End of "$Id$".
  */
index 537343a45afc672141df4800cc6550ef96339112..7a32226fb15e6ea0327613126a24643e47262c01 100644 (file)
@@ -81,9 +81,9 @@ notify.o: i18n.h transcode.h
 options.o: cups.h ipp.h http.h versioning.h ppd.h array.h file.h language.h
 options.o: string.h ../config.h debug.h
 page.o: ppd.h array.h versioning.h file.h string.h ../config.h
-ppd.o: globals.h string.h ../config.h http-private.h http.h versioning.h
-ppd.o: md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
-ppd.o: i18n.h transcode.h debug.h
+ppd.o: ppd-private.h cups.h ipp.h http.h versioning.h ppd.h array.h file.h
+ppd.o: language.h globals.h string.h ../config.h http-private.h md5.h
+ppd.o: ipp-private.h i18n.h transcode.h debug.h
 request.o: globals.h string.h ../config.h http-private.h http.h versioning.h
 request.o: md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
 request.o: i18n.h transcode.h debug.h
@@ -207,9 +207,9 @@ notify.32.o: notify.c  i18n.h transcode.h
 options.32.o: options.c  cups.h ipp.h http.h versioning.h ppd.h array.h file.h language.h
 options.32.o: options.c  string.h ../config.h debug.h
 page.32.o: page.c  ppd.h array.h versioning.h file.h string.h ../config.h
-ppd.32.o: ppd.c  globals.h string.h ../config.h http-private.h http.h versioning.h
-ppd.32.o: ppd.c  md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
-ppd.32.o: ppd.c  i18n.h transcode.h debug.h
+ppd.32.o: ppd.c  ppd-private.h cups.h ipp.h http.h versioning.h ppd.h array.h file.h
+ppd.32.o: ppd.c  language.h globals.h string.h ../config.h http-private.h md5.h
+ppd.32.o: ppd.c  ipp-private.h i18n.h transcode.h debug.h
 request.32.o: request.c  globals.h string.h ../config.h http-private.h http.h versioning.h
 request.32.o: request.c  md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
 request.32.o: request.c  i18n.h transcode.h debug.h
@@ -333,9 +333,9 @@ notify.64.o: notify.c  i18n.h transcode.h
 options.64.o: options.c  cups.h ipp.h http.h versioning.h ppd.h array.h file.h language.h
 options.64.o: options.c  string.h ../config.h debug.h
 page.64.o: page.c  ppd.h array.h versioning.h file.h string.h ../config.h
-ppd.64.o: ppd.c  globals.h string.h ../config.h http-private.h http.h versioning.h
-ppd.64.o: ppd.c  md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
-ppd.64.o: ppd.c  i18n.h transcode.h debug.h
+ppd.64.o: ppd.c  ppd-private.h cups.h ipp.h http.h versioning.h ppd.h array.h file.h
+ppd.64.o: ppd.c  language.h globals.h string.h ../config.h http-private.h md5.h
+ppd.64.o: ppd.c  ipp-private.h i18n.h transcode.h debug.h
 request.64.o: request.c  globals.h string.h ../config.h http-private.h http.h versioning.h
 request.64.o: request.c  md5.h ipp-private.h ipp.h cups.h ppd.h array.h file.h language.h
 request.64.o: request.c  i18n.h transcode.h debug.h
index 042bfdcec6f74bc87fa0bbc3f00ea7d280f4f5c9..f497f046f1049d02910bac3368f178de28329612 100644 (file)
@@ -234,7 +234,7 @@ cupsResolveConflicts(
   for (i = 0; i < *num_options; i ++)
     num_newopts = cupsAddOption((*options)[i].name, (*options)[i].value,
                                 num_newopts, &newopts);
-  if (option)
+  if (option && strcasecmp(option, "Collate"))
     num_newopts = cupsAddOption(option, choice, num_newopts, &newopts);
 
  /*
@@ -375,18 +375,28 @@ cupsResolveConflicts(
   }
 
  /*
-  * Free either the old or the new options depending on whether we had to
-  * apply any resolvers...
+  * Free the caller's option array...
   */
 
-  if (resolvers)
-  {
-    cupsFreeOptions(*num_options, *options);
-    *num_options = num_newopts;
-    *options     = newopts;
-  }
+  cupsFreeOptions(*num_options, *options);
+
+ /*
+  * If Collate is the option we are testing, add it here.  Otherwise, remove
+  * any Collate option from the resolve list since the filters automatically
+  * handle manual collation...
+  */
+
+  if (option && !strcasecmp(option, "Collate"))
+    num_newopts = cupsAddOption(option, choice, num_newopts, &newopts);
   else
-    cupsFreeOptions(num_newopts, newopts);
+    num_newopts = cupsRemoveOption("Collate", num_newopts, &newopts);
+
+ /*
+  * Return the new list of options to the caller...
+  */
+
+  *num_options = num_newopts;
+  *options     = newopts;
 
   cupsArrayDelete(pass);
   cupsArrayDelete(resolvers);
@@ -528,7 +538,7 @@ ppd_load_constraints(ppd_file_t *ppd)       /* I - PPD file */
 
       for (i = 0, vptr = strchr(constattr->value, '*');
            vptr;
-          i ++, vptr = strchr(vptr + 1, '*'), constptr ++)
+          i ++, vptr = strchr(vptr, '*'), constptr ++)
       {
        /*
         * Extract "*Option Choice" or just "*Option"...
@@ -544,10 +554,7 @@ ppd_load_constraints(ppd_file_t *ppd)      /* I - PPD file */
          vptr ++;
 
         if (*vptr == '*')
-       {
-         vptr --;
          choice[0] = '\0';
-       }
        else
        {
          for (ptr = choice; *vptr && !isspace(*vptr & 255); vptr ++)
@@ -568,9 +575,10 @@ ppd_load_constraints(ppd_file_t *ppd)      /* I - PPD file */
         constptr->installable = ppd_is_installable(installable, option);
        consts->installable   |= constptr->installable;
 
-        if (!constptr->option)
+        if (!constptr->option || (!constptr->choice && choice[0]))
        {
-         DEBUG_printf(("ppd_load_constraints: Unknown option %s!\n", option));
+         DEBUG_printf(("ppd_load_constraints: Unknown option *%s %s!\n",
+                       option, choice));
          break;
        }
       }
@@ -646,10 +654,10 @@ ppd_load_constraints(ppd_file_t *ppd)     /* I - PPD file */
                                                     oldconst->option1);
       }
 
-      if (!constptr[0].option)
+      if (!constptr[0].option || (!constptr[0].choice && oldconst->choice1[0]))
       {
-        DEBUG_printf(("ppd_load_constraints: Unknown option %s!\n",
-                     oldconst->option1));
+        DEBUG_printf(("ppd_load_constraints: Unknown option *%s %s!\n",
+                     oldconst->option1, oldconst->choice1));
         free(consts->constraints);
        free(consts);
        continue;
@@ -671,10 +679,10 @@ ppd_load_constraints(ppd_file_t *ppd)     /* I - PPD file */
                                                     oldconst->option2);
       }
 
-      if (!constptr->option)
+      if (!constptr[1].option || (!constptr[1].choice && oldconst->choice2[0]))
       {
-        DEBUG_printf(("ppd_load_constraints: Unknown option %s!\n",
-                     oldconst->option2));
+        DEBUG_printf(("ppd_load_constraints: Unknown option *%s %s!\n",
+                     oldconst->option2, oldconst->choice2));
         free(consts->constraints);
        free(consts);
        continue;
index 3e78be539eabe344155a6c01ae4a6e028d4e494d..fed81fc48ae09c5e947b33fadd1268fc294d2969 100644 (file)
@@ -618,7 +618,40 @@ ppdEmitString(ppd_file_t    *ppd,  /* I - PPD file record */
 
   for (i = 0, bufsize = 1; i < count; i ++)
   {
-    if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL)
+    if (section == PPD_ORDER_JCL)
+    {
+      if (!strcasecmp(choices[i]->choice, "Custom") &&
+         (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword))
+             != NULL)
+      {
+       /*
+        * Add space to account for custom parameter substitution...
+       */
+
+        for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
+            cparam;
+            cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
+       {
+          switch (cparam->type)
+         {
+           case PPD_CUSTOM_CURVE :
+           case PPD_CUSTOM_INVCURVE :
+           case PPD_CUSTOM_POINTS :
+           case PPD_CUSTOM_REAL :
+           case PPD_CUSTOM_INT :
+               bufsize += 10;
+               break;
+
+           case PPD_CUSTOM_PASSCODE :
+           case PPD_CUSTOM_PASSWORD :
+           case PPD_CUSTOM_STRING :
+               bufsize += strlen(cparam->current.custom_string);
+               break;
+          }
+       }
+      }
+    }
+    else if (section != PPD_ORDER_EXIT)
     {
       bufsize += 3;                    /* [{\n */
 
@@ -698,7 +731,89 @@ ppdEmitString(ppd_file_t    *ppd,  /* I - PPD file record */
   */
 
   for (i = 0, bufptr = buffer; i < count; i ++, bufptr += strlen(bufptr))
-    if (section != PPD_ORDER_EXIT && section != PPD_ORDER_JCL)
+    if (section == PPD_ORDER_JCL)
+    {
+      if (!strcasecmp(choices[i]->choice, "Custom") &&
+          (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword))
+             != NULL)
+      {
+       /*
+        * Handle substitutions in custom JCL options...
+       */
+
+       char    *cptr;                  /* Pointer into code */
+       int     pnum;                   /* Parameter number */
+
+
+        for (cptr = choices[i]->code; *cptr && bufptr < bufend;)
+       {
+         if (*cptr == '\\')
+         {
+           cptr ++;
+
+           if (isdigit(*cptr & 255))
+           {
+            /*
+             * Substitute parameter...
+             */
+
+              pnum = *cptr++ - '0';
+             while (isalnum(*cptr & 255))
+               pnum = pnum * 10 + *cptr - '0';
+
+              for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
+                  cparam;
+                  cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
+               if (cparam->order == pnum)
+                 break;
+
+              if (cparam)
+             {
+               switch (cparam->type)
+               {
+                 case PPD_CUSTOM_CURVE :
+                 case PPD_CUSTOM_INVCURVE :
+                 case PPD_CUSTOM_POINTS :
+                 case PPD_CUSTOM_REAL :
+                     bufptr = _cupsStrFormatd(bufptr, bufend,
+                                              cparam->current.custom_real,
+                                              loc);
+                     break;
+
+                 case PPD_CUSTOM_INT :
+                     snprintf(bufptr, bufend - bufptr, "%d",
+                              cparam->current.custom_int);
+                     bufptr += strlen(bufptr);
+                     break;
+
+                 case PPD_CUSTOM_PASSCODE :
+                 case PPD_CUSTOM_PASSWORD :
+                 case PPD_CUSTOM_STRING :
+                     strlcpy(bufptr, cparam->current.custom_string,
+                             bufend - bufptr);
+                     bufptr += strlen(bufptr);
+                     break;
+               }
+             }
+           }
+           else if (*cptr)
+             *bufptr++ = *cptr++;
+         }
+         else
+           *bufptr++ = *cptr++;
+       }
+      }
+      else
+      {
+       /*
+        * Otherwise just copy the option code directly...
+       */
+
+        strlcpy(bufptr, choices[i]->code, bufend - bufptr + 1);
+        bufptr += strlen(bufptr);
+      }
+    }
+    else if (section != PPD_ORDER_EXIT)
     {
      /*
       * Add wrapper commands to prevent printer errors for unsupported
@@ -831,8 +946,7 @@ ppdEmitString(ppd_file_t    *ppd,   /* I - PPD file record */
        }
       }
       else if (!strcasecmp(choices[i]->choice, "Custom") &&
-               (coption = ppdFindCustomOption(ppd,
-                                             choices[i]->option->keyword))
+               (coption = ppdFindCustomOption(ppd, choices[i]->option->keyword))
                   != NULL)
       {
        /*
index 53c15631aa476abddb24700832fe77a480d615ea..8f34b3ccc157a3dfafbfbdc4a04c6640877040d2 100644 (file)
@@ -336,5 +336,6 @@ _ppdOpenFd
 _ppdOpenFile
 _ppdPageLength
 _ppdPageSize
+_ppdPageSizeLimits
 _ppdPageWidth
 _ppdSetConformance
index b4e325697f6adac81e0113aeb41554b2e1e9fe5d..01a723e68def24713d837b981eaa147f7818ffe8 100644 (file)
@@ -163,6 +163,176 @@ ppdPageSize(ppd_file_t *ppd,              /* I - PPD file record */
 }
 
 
+/*
+ * 'ppdPageSizeLimits()' - Return the custom page size limits.
+ *
+ * This function returns the minimum and maximum custom page sizes and printable
+ * areas based on the currently-marked (selected) options.
+ *
+ * If the specified PPD file does not support custom page sizes, both
+ * "minimum" and "maximum" are filled with zeroes.
+ *
+ * @since CUPS 1.4@
+ */
+
+int                                    /* O - 1 if custom sizes are supported, 0 otherwise */
+ppdPageSizeLimits(ppd_file_t *ppd,     /* I - PPD file record */
+                  ppd_size_t *minimum, /* O - Minimum custom size */
+                 ppd_size_t *maximum)  /* O - Maximum custom size */
+{
+  ppd_choice_t *qualifier2,            /* Second media qualifier */
+               *qualifier3;            /* Third media qualifier */
+  ppd_attr_t   *attr;                  /* Attribute */
+  float                width,                  /* Min/max width */
+               length;                 /* Min/max length */
+  char         spec[PPD_MAX_NAME];     /* Selector for min/max */
+
+
+ /*
+  * Range check input...
+  */
+
+  if (!ppd || !ppd->variable_sizes || !minimum || !maximum)
+  {
+    if (minimum)
+      memset(minimum, 0, sizeof(ppd_size_t));
+
+    if (maximum)
+      memset(maximum, 0, sizeof(ppd_size_t));
+
+    return (0);
+  }
+
+ /*
+  * See if we have the cupsMediaQualifier2 and cupsMediaQualifier3 attributes...
+  */
+
+  cupsArraySave(ppd->sorted_attrs);
+
+  if ((attr = ppdFindAttr(ppd, "cupsMediaQualifier2", NULL)) != NULL &&
+      attr->value)
+    qualifier2 = ppdFindMarkedChoice(ppd, attr->value);
+  else
+    qualifier2 = NULL;
+
+  if ((attr = ppdFindAttr(ppd, "cupsMediaQualifier3", NULL)) != NULL &&
+      attr->value)
+    qualifier3 = ppdFindMarkedChoice(ppd, attr->value);
+  else
+    qualifier3 = NULL;
+
+ /*
+  * Figure out the current minimum width and length...
+  */
+
+  if (qualifier2)
+  {
+   /*
+    * Try getting cupsMinSize...
+    */
+
+    if (qualifier3)
+    {
+      snprintf(spec, sizeof(spec), ".%s.%s", qualifier2->choice,
+              qualifier3->choice);
+      attr = ppdFindAttr(ppd, "cupsMinSize", spec);
+    }
+    else
+      attr = NULL;
+
+    if (!attr)
+    {
+      snprintf(spec, sizeof(spec), ".%s.", qualifier2->choice);
+      attr = ppdFindAttr(ppd, "cupsMinSize", spec);
+    }
+
+    if (!attr && qualifier3)
+    {
+      snprintf(spec, sizeof(spec), "..%s", qualifier3->choice);
+      attr = ppdFindAttr(ppd, "cupsMinSize", spec);
+    }
+
+    if (!attr ||
+        (attr->value && sscanf(attr->value, "%f%f", &width, &length) != 2))
+    {
+      width  = ppd->custom_min[0];
+      length = ppd->custom_min[1];
+    }
+  }
+  else
+  {
+    width  = ppd->custom_min[0];
+    length = ppd->custom_min[1];
+  }
+
+  minimum->width  = width;
+  minimum->length = length;
+  minimum->left   = ppd->custom_margins[0];
+  minimum->bottom = ppd->custom_margins[1];
+  minimum->right  = width - ppd->custom_margins[2];
+  minimum->top    = length - ppd->custom_margins[3];
+
+ /*
+  * Figure out the current maximum width and length...
+  */
+
+  if (qualifier2)
+  {
+   /*
+    * Try getting cupsMaxSize...
+    */
+
+    if (qualifier3)
+    {
+      snprintf(spec, sizeof(spec), ".%s.%s", qualifier2->choice,
+              qualifier3->choice);
+      attr = ppdFindAttr(ppd, "cupsMaxSize", spec);
+    }
+    else
+      attr = NULL;
+
+    if (!attr)
+    {
+      snprintf(spec, sizeof(spec), ".%s.", qualifier2->choice);
+      attr = ppdFindAttr(ppd, "cupsMaxSize", spec);
+    }
+
+    if (!attr && qualifier3)
+    {
+      snprintf(spec, sizeof(spec), "..%s", qualifier3->choice);
+      attr = ppdFindAttr(ppd, "cupsMaxSize", spec);
+    }
+
+    if (!attr ||
+        (attr->value && sscanf(attr->value, "%f%f", &width, &length) != 2))
+    {
+      width  = ppd->custom_max[0];
+      length = ppd->custom_max[1];
+    }
+  }
+  else
+  {
+    width  = ppd->custom_max[0];
+    length = ppd->custom_max[1];
+  }
+
+  maximum->width  = width;
+  maximum->length = length;
+  maximum->left   = ppd->custom_margins[0];
+  maximum->bottom = ppd->custom_margins[1];
+  maximum->right  = width - ppd->custom_margins[2];
+  maximum->top    = length - ppd->custom_margins[3];
+
+ /*
+  * Return the min and max...
+  */
+
+  cupsArrayRestore(ppd->sorted_attrs);
+
+  return (1);
+}
+
+
 /*
  * 'ppdPageWidth()' - Get the page width for the given size.
  */
index 436dd05f293c023105cdf4d25f6147d79e838ae4..75db5c5acf87912018119ef9ed80f8b6de818cd7 100644 (file)
@@ -59,6 +59,7 @@
  * Include necessary headers.
  */
 
+#include "ppd-private.h"
 #include "globals.h"
 #include "debug.h"
 #include <stdlib.h>
@@ -291,6 +292,26 @@ ppdClose(ppd_file_t *ppd)          /* I - PPD file record */
 
   cupsArrayDelete(ppd->coptions);
 
+ /*
+  * Free constraints...
+  */
+
+  if (ppd->cups_uiconstraints)
+  {
+    _ppd_cups_uiconsts_t *consts;      /* Current constraints */
+
+
+    for (consts = (_ppd_cups_uiconsts_t *)cupsArrayFirst(ppd->cups_uiconstraints);
+         consts;
+        consts = (_ppd_cups_uiconsts_t *)cupsArrayNext(ppd->cups_uiconstraints))
+    {
+      free(consts->constraints);
+      free(consts);
+    }
+
+    cupsArrayDelete(ppd->cups_uiconstraints);
+  }
+
  /*
   * Free the whole record...
   */
@@ -1042,6 +1063,9 @@ ppdOpen2(cups_file_t *fp)         /* I - File to read from */
                sizeof(choice->text));
 
        choice->code = _cupsStrAlloc(string);
+
+       if (custom_option->section == PPD_ORDER_JCL)
+         ppd_decode(choice->code);
       }
 
      /*
index 4261aae1ae6bf893e099e5eb832cd44d26d25ae3..325c36245cc7f3175fc59d884f59093db59af117 100644 (file)
@@ -409,6 +409,9 @@ extern ppd_attr_t   *ppdLocalizeAttr(ppd_file_t *ppd, const char *keyword,
                                         const char *spec);
 extern const char      *ppdLocalizeMarkerName(ppd_file_t *ppd,
                                               const char *name) _CUPS_API_1_4;
+extern int             ppdPageSizeLimits(ppd_file_t *ppd,
+                                         ppd_size_t *minimum,
+                                         ppd_size_t *maximum) _CUPS_API_1_4;
 
 
 /*
index 9cd9d22e5efeecf10b0dd68c539855e39a8f96ba..a553ba4b762226f33c7c67cb2813c101e2a489f1 100644 (file)
 *ParamCustomPageSize HeightOffset/Height Offset: 4 points 0 0
 *ParamCustomPageSize Orientation:  5 int 0 0
 
+*cupsMediaQualifier2: InputSlot
+*cupsMediaQualifier3: Quality
+*cupsMaxSize .Manual.: "1000 1000"
+*cupsMinSize .Manual.: "100 100"
+*cupsMinSize .Manual.Photo: "200 200"
+*cupsMinSize ..Photo: "300 300"
+
 *OpenUI *InputSlot/Input Slot: PickOne
 *OrderDependency: 20 AnySetup *InputSlot
 *DefaultInputSlot: Tray
index 10f11650f4095d2f9fd4150e851d0c938389236f..943e390e17a84deb9b3e768df96e2ebd84a3246e 100644 (file)
@@ -112,6 +112,8 @@ main(int  argc,                             /* I - Number of command-line arguments */
   const char   *text;                  /* Localized text */
   int          num_options;            /* Number of options */
   cups_option_t        *options;               /* Options */
+  ppd_size_t   minsize,                /* Minimum size */
+               maxsize;                /* Maximum size */
 
 
   status = 0;
@@ -254,6 +256,30 @@ main(int  argc,                            /* I - Number of command-line arguments */
       status ++;
     }
 
+   /*
+    * ppdPageSizeLimits
+    */
+
+    fputs("ppdPageSizeLimits: ", stdout);
+    if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
+    {
+      if (minsize.width != 36 || minsize.length != 36 ||
+          maxsize.width != 1080 || maxsize.length != 86400)
+      {
+        printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
+              "expected min=36x36, max=1080x86400)\n", minsize.width,
+              minsize.length, maxsize.width, maxsize.length);
+        status ++;
+      }
+      else
+        puts("PASS");
+    }
+    else
+    {
+      puts("FAIL (returned 0)");
+      status ++;
+    }
+
    /*
     * Test localization...
     */
@@ -477,6 +503,98 @@ main(int  argc,                            /* I - Number of command-line arguments */
       puts("FAIL (Duplex=None conflicted)");
       status ++;
     }
+
+   /*
+    * ppdPageSizeLimits
+    */
+
+    ppdMarkDefaults(ppd);
+
+    fputs("ppdPageSizeLimits(default): ", stdout);
+    if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
+    {
+      if (minsize.width != 36 || minsize.length != 36 ||
+          maxsize.width != 1080 || maxsize.length != 86400)
+      {
+        printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
+              "expected min=36x36, max=1080x86400)\n", minsize.width,
+              minsize.length, maxsize.width, maxsize.length);
+        status ++;
+      }
+      else
+        puts("PASS");
+    }
+    else
+    {
+      puts("FAIL (returned 0)");
+      status ++;
+    }
+
+    ppdMarkOption(ppd, "InputSlot", "Manual");
+
+    fputs("ppdPageSizeLimits(InputSlot=Manual): ", stdout);
+    if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
+    {
+      if (minsize.width != 100 || minsize.length != 100 ||
+          maxsize.width != 1000 || maxsize.length != 1000)
+      {
+        printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
+              "expected min=100x100, max=1000x1000)\n", minsize.width,
+              minsize.length, maxsize.width, maxsize.length);
+        status ++;
+      }
+      else
+        puts("PASS");
+    }
+    else
+    {
+      puts("FAIL (returned 0)");
+      status ++;
+    }
+
+    ppdMarkOption(ppd, "Quality", "Photo");
+
+    fputs("ppdPageSizeLimits(Quality=Photo): ", stdout);
+    if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
+    {
+      if (minsize.width != 200 || minsize.length != 200 ||
+          maxsize.width != 1000 || maxsize.length != 1000)
+      {
+        printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
+              "expected min=200x200, max=1000x1000)\n", minsize.width,
+              minsize.length, maxsize.width, maxsize.length);
+        status ++;
+      }
+      else
+        puts("PASS");
+    }
+    else
+    {
+      puts("FAIL (returned 0)");
+      status ++;
+    }
+
+    ppdMarkOption(ppd, "InputSlot", "Tray");
+
+    fputs("ppdPageSizeLimits(Quality=Photo): ", stdout);
+    if (ppdPageSizeLimits(ppd, &minsize, &maxsize))
+    {
+      if (minsize.width != 300 || minsize.length != 300 ||
+          maxsize.width != 1080 || maxsize.length != 86400)
+      {
+        printf("FAIL (got min=%.0fx%.0f, max=%.0fx%.0f, "
+              "expected min=300x300, max=1080x86400)\n", minsize.width,
+              minsize.length, maxsize.width, maxsize.length);
+        status ++;
+      }
+      else
+        puts("PASS");
+    }
+    else
+    {
+      puts("FAIL (returned 0)");
+      status ++;
+    }
   }
   else
   {
index 125c7b29b3448c85227bdc94c539c237e7a99386..2bb61a07d22a721ba9a70ec605352657aa43a283 100644 (file)
@@ -345,6 +345,7 @@ conflicts.">ppdMarkOption</a></li>
 <li><a href="#ppdOpenFile" title="Read a PPD file into memory.">ppdOpenFile</a></li>
 <li><a href="#ppdPageLength" title="Get the page length for the given size.">ppdPageLength</a></li>
 <li><a href="#ppdPageSize" title="Get the page size record for the given size.">ppdPageSize</a></li>
+<li><a href="#ppdPageSizeLimits" title="Return the custom page size limits.">ppdPageSizeLimits</a></li>
 <li><a href="#ppdPageWidth" title="Get the page width for the given size.">ppdPageWidth</a></li>
 <li><a href="#ppdSetConformance" title="Set the conformance level for PPD files.">ppdSetConformance</a></li>
 </ul>
@@ -1368,6 +1369,33 @@ float ppdPageLength (<br>
 </dl>
 <h4 class="returnvalue">Return Value</h4>
 <p class="description">Size record for page or NULL</p>
+<h3 class="function"><span class="info">&nbsp;CUPS 1.4&nbsp;</span><a name="ppdPageSizeLimits">ppdPageSizeLimits</a></h3>
+<p class="description">Return the custom page size limits.</p>
+<p class="code">
+int ppdPageSizeLimits (<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_size_t">ppd_size_t</a> *minimum,<br>
+&nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_size_t">ppd_size_t</a> *maximum<br>
+);</p>
+<h4 class="parameters">Parameters</h4>
+<dl>
+<dt>ppd</dt>
+<dd class="description">PPD file record</dd>
+<dt>minimum</dt>
+<dd class="description">Minimum custom size</dd>
+<dt>maximum</dt>
+<dd class="description">Maximum custom size</dd>
+</dl>
+<h4 class="returnvalue">Return Value</h4>
+<p class="description">1 if custom sizes are supported, 0 otherwise</p>
+<h4 class="discussion">Discussion</h4>
+<p class="discussion">This function returns the minimum and maximum custom page sizes and printable
+areas based on the currently-marked (selected) options.<br>
+<br>
+If the specified PPD file does not support custom page sizes, both
+&quot;minimum&quot; and &quot;maximum&quot; are filled with zeroes.
+
+</p>
 <h3 class="function"><a name="ppdPageWidth">ppdPageWidth</a></h3>
 <p class="description">Get the page width for the given size.</p>
 <p class="code">
index cd8b6c26ea557c73aaf5a7a433d3811ab6736665..b8fbeaa5c8086d1ad01cd8c651de5c3f7da498ec 100644 (file)
@@ -8928,6 +8928,8 @@ release_job(cupsd_client_t  *con, /* I - Client connection */
   cupsdLogJob(job, CUPSD_LOG_INFO, "Released by \"%s\".", username);
 
   con->response->request.status.status_code = IPP_OK;
+
+  cupsdCheckJobs();
 }
 
 
@@ -9971,6 +9973,7 @@ set_job_attrs(cupsd_client_t  *con,       /* I - Client connection */
                                        /* Resource portion of URI */
   int                  port;           /* Port portion of URI */
   int                  event;          /* Events? */
+  int                  check_jobs;     /* Check jobs? */
 
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_job_attrs(%p[%d], %s)", con,
@@ -10072,7 +10075,8 @@ set_job_attrs(cupsd_client_t  *con,     /* I - Client connection */
 
   cupsdLoadJob(job);
 
-  event = 0;
+  check_jobs = 0;
+  event      = 0;
 
   for (attr = con->request->attrs; attr; attr = attr->next)
   {
@@ -10138,9 +10142,13 @@ set_job_attrs(cupsd_client_t  *con,    /* I - Client connection */
       }
       else if (con->response->request.status.status_code == IPP_OK)
       {
+        cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-priority to %d",
+                   attr->values[0].integer);
         cupsdSetJobPriority(job, attr->values[0].integer);
-        event |= CUPSD_EVENT_JOB_CONFIG_CHANGED |
-                CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED;
+
+       check_jobs = 1;
+        event      |= CUPSD_EVENT_JOB_CONFIG_CHANGED |
+                     CUPSD_EVENT_PRINTER_QUEUE_ORDER_CHANGED;
       }
     }
     else if (!strcmp(attr->name, "job-state"))
@@ -10170,10 +10178,14 @@ set_job_attrs(cupsd_client_t  *con,   /* I - Client connection */
              }
               else if (con->response->request.status.status_code == IPP_OK)
              {
+               cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-state to %d",
+                           attr->values[0].integer);
+
                job->state->values[0].integer = attr->values[0].integer;
                job->state_value = (ipp_jstate_t)attr->values[0].integer;
 
                 event |= CUPSD_EVENT_JOB_STATE;
+               check_jobs = 1;
              }
              break;
 
@@ -10197,7 +10209,13 @@ set_job_attrs(cupsd_client_t  *con,    /* I - Client connection */
                return;
              }
               else if (con->response->request.status.status_code == IPP_OK)
+             {
+               cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-state to %d",
+                           attr->values[0].integer);
                 cupsdCancelJob(job, 0, (ipp_jstate_t)attr->values[0].integer);
+
+                check_jobs = 1;
+             }
              break;
        }
       }
@@ -10233,6 +10251,8 @@ set_job_attrs(cupsd_client_t  *con,     /* I - Client connection */
 
       if (!strcmp(attr->name, "job-hold-until"))
       {
+        cupsdLogJob(job, CUPSD_LOG_DEBUG, "Setting job-hold-until to %s",
+                   attr->values[0].string.text);
         cupsdSetJobHoldUntil(job, attr->values[0].string.text);
 
        if (!strcmp(attr->values[0].string.text, "no-hold"))
@@ -10240,7 +10260,8 @@ set_job_attrs(cupsd_client_t  *con,     /* I - Client connection */
        else
          cupsdHoldJob(job);
 
-        event |= CUPSD_EVENT_JOB_CONFIG_CHANGED | CUPSD_EVENT_JOB_STATE;
+        check_jobs = 1;
+        event      |= CUPSD_EVENT_JOB_CONFIG_CHANGED | CUPSD_EVENT_JOB_STATE;
       }
     }
     else if (attr->value_tag == IPP_TAG_DELETEATTR)
@@ -10306,7 +10327,8 @@ set_job_attrs(cupsd_client_t  *con,     /* I - Client connection */
   * Start jobs if possible...
   */
 
-  cupsdCheckJobs();
+  if (check_jobs)
+    cupsdCheckJobs();
 }
 
 
index 0669ec028a33cc42f35b15e31a066c2e212865d6..e0bd77534006150ce34de4385fe410eacb1e7bd3 100644 (file)
@@ -373,8 +373,9 @@ cupsdCheckJobs(void)
     */
 
     cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                    "cupsdCheckJobs: Job %d: state_value=%d, loaded=%s",
-                    job->id, job->state_value, job->attrs ? "yes" : "no");
+                    "cupsdCheckJobs: Job %d: dest=%s, dtype=%x, "
+                   "state_value=%d, loaded=%s", job->id, job->dest, job->dtype,
+                   job->state_value, job->attrs ? "yes" : "no");
 
     if (job->state_value == IPP_JOB_HELD &&
         job->hold_until &&
@@ -955,8 +956,6 @@ cupsdHoldJob(cupsd_job_t *job)              /* I - Job data */
 
   job->dirty = 1;
   cupsdMarkDirty(CUPSD_DIRTY_JOBS);
-
-  cupsdCheckJobs();
 }
 
 
@@ -1380,13 +1379,19 @@ cupsdReleaseJob(cupsd_job_t *job)       /* I - Job */
 
   if (job->state_value == IPP_JOB_HELD)
   {
+   /*
+    * Add trailing banner as needed...
+    */
+
+    if (job->pending_timeout)
+      cupsdTimeoutJob(job);
+
     DEBUG_puts("cupsdReleaseJob: setting state to pending...");
 
     job->state->values[0].integer = IPP_JOB_PENDING;
     job->state_value              = IPP_JOB_PENDING;
     job->dirty = 1;
     cupsdMarkDirty(CUPSD_DIRTY_JOBS);
-    cupsdCheckJobs();
   }
 }
 
@@ -1418,8 +1423,6 @@ cupsdRestartJob(cupsd_job_t *job) /* I - Job */
 
     if (old_state > IPP_JOB_STOPPED)
       cupsArrayAdd(ActiveJobs, job);
-
-    cupsdCheckJobs();
   }
 }
 
index 1eb10c2d05a8df72484735a4a04fddad9a8d68d1..dc2e23297afbea2bef98b934038ba6d8e1060390 100644 (file)
@@ -47,7 +47,7 @@ static char   *log_line = NULL;       /* Line for output file */
  */
 
 static int     check_log_file(cups_file_t **lf, const char *logname);
-static char    *format_log_line(const char *message, va_list ap);
+static int     format_log_line(const char *message, va_list ap);
 
 
 /*
@@ -175,8 +175,8 @@ cupsdLogJob(cupsd_job_t *job,               /* I - Job */
            ...)                        /* I - Additional arguments as needed */
 {
   va_list              ap;             /* Argument pointer */
-  char                 jobmsg[1024],   /* Format string for job message */
-                       *line;          /* Message line */
+  char                 jobmsg[1024];   /* Format string for job message */
+  int                  status;         /* Formatting status */
 
 
  /*
@@ -192,12 +192,16 @@ cupsdLogJob(cupsd_job_t *job,             /* I - Job */
 
   snprintf(jobmsg, sizeof(jobmsg), "[Job %d] %s", job->id, message);
 
-  va_start(ap, message);
-  line = format_log_line(jobmsg, ap);
-  va_end(ap);
+  do
+  {
+    va_start(ap, message);
+    status = format_log_line(jobmsg, ap);
+    va_end(ap);
+  }
+  while (status == 0);
 
-  if (line)
-    return (cupsdWriteErrorLog(level, line));
+  if (status > 0)
+    return (cupsdWriteErrorLog(level, log_line));
   else
     return (cupsdWriteErrorLog(CUPSD_LOG_ERROR,
                                "Unable to allocate memory for log line!"));
@@ -214,7 +218,7 @@ cupsdLogMessage(int        level,   /* I - Log level */
                ...)                    /* I - Additional args as needed */
 {
   va_list              ap;             /* Argument pointer */
-  char                 *line;          /* Message line */
+  int                  status;         /* Formatting status */
 
 
  /*
@@ -241,12 +245,16 @@ cupsdLogMessage(int        level, /* I - Log level */
   * Format and write the log message...
   */
 
-  va_start(ap, message);
-  line = format_log_line(message, ap);
-  va_end(ap);
+  do
+  {
+    va_start(ap, message);
+    status = format_log_line(message, ap);
+    va_end(ap);
+  }
+  while (status == 0);
 
-  if (line)
-    return (cupsdWriteErrorLog(level, line));
+  if (status > 0)
+    return (cupsdWriteErrorLog(level, log_line));
   else
     return (cupsdWriteErrorLog(CUPSD_LOG_ERROR,
                                "Unable to allocate memory for log line!"));
@@ -870,11 +878,11 @@ check_log_file(cups_file_t **lf,  /* IO - Log file */
  * to format_log_line()...
  */
 
-static char *                          /* O - Text or NULL on error */
+static int                             /* O - -1 for fatal, 0 for retry, 1 for success */
 format_log_line(const char *message,   /* I - Printf-style format string */
                 va_list    ap)         /* I - Argument list */
 {
-  int  len;                            /* Length of formatted line */
+  int          len;                    /* Length of formatted line */
 
 
  /*
@@ -887,7 +895,7 @@ format_log_line(const char *message,        /* I - Printf-style format string */
     log_line     = malloc(log_linesize);
 
     if (!log_line)
-      return (NULL);
+      return (-1);
   }
 
  /*
@@ -918,12 +926,12 @@ format_log_line(const char *message,      /* I - Printf-style format string */
     {
       log_line     = temp;
       log_linesize = len;
-    }
 
-    vsnprintf(log_line, log_linesize, message, ap);
+      return (0);
+    }
   }
 
-  return (log_line);
+  return (1);
 }
 
 
index c675e090d01bbeb3992d0bbe726f58826d14306c..df8f7f24cc02fb730c313cc2872d9d7d8ac1cae1 100644 (file)
@@ -2402,7 +2402,8 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
              if ((duplex = ppdFindOption(ppd, "KD03Duplex")) == NULL)
                duplex = ppdFindOption(ppd, "JCLDuplex");
 
-       if (duplex && duplex->num_choices > 1)
+       if (duplex && duplex->num_choices > 1 &&
+           !ppdInstallableConflict(ppd, duplex->keyword, "DuplexTumble"))
        {
          p->type |= CUPS_PRINTER_DUPLEX;
 
index f376dd46ef0223cd87aae025d76a9eca4a42f9f9..b8052b3b588ae4114d2d761819e40ea8b101c185 100644 (file)
@@ -1767,7 +1767,7 @@ check_constraints(ppd_file_t *ppd,        /* I - PPD file */
 
       for (vptr = strchr(constattr->value, '*');
            vptr;
-          vptr = strchr(vptr + 1, '*'))
+          vptr = strchr(vptr, '*'))
       {
        /*
         * Extract "*Option Choice" or just "*Option"...
@@ -1783,10 +1783,7 @@ check_constraints(ppd_file_t *ppd,       /* I - PPD file */
          vptr ++;
 
         if (*vptr == '*')
-       {
-         vptr --;
          choice[0] = '\0';
-       }
        else
        {
          for (ptr = choice; *vptr && !isspace(*vptr & 255); vptr ++)
@@ -2533,7 +2530,8 @@ check_translations(ppd_file_t *ppd,       /* I - PPD file */
 
        strlcpy(ll, language, sizeof(ll));
 
-       if (!cupsArrayFind(languages, ll) && strcmp(ll, "zh"))
+       if (!cupsArrayFind(languages, ll) &&
+           strcmp(ll, "zh") && strcmp(ll, "en"))
        {
          if (!warn && !errors && !verbose)
            _cupsLangPuts(stdout, _(" FAIL\n"));
index 53ede17d56cf117b9e45734b7a039c2a8b0f95af..c25dfc49d0308949ed3931ecdcbe39737546fb64 100755 (executable)
@@ -75,6 +75,12 @@ sed -e '1,$s/@CUPS_VERSION@/'$version'/' \
 tar cjf cups-$fileversion-source.tar.bz2 cups-$version
 echo "..."
 
+if test -x /usr/bin/md5sum; then
+       (cd /tmp; md5sum cups-$fileversion-source.tar.* | awk '{print $1, "'$fileversion' cups/'$fileversion'/" $2}')
+elif test -x /sbin/md5; then
+       (cd /tmp; md5 cups-$fileversion-source.tar.* | awk '{print $4, "'$fileversion' cups/'$fileversion'/" substr($2, 2, length($2) - 2)}')
+fi
+
 echo Removing temporary files...
 rm -rf cups-$version