]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Load cups into easysw/current.
authorjlovell <jlovell@a1ca3aef-8c08-0410-bb20-df032aa958be>
Fri, 4 May 2007 21:17:48 +0000 (21:17 +0000)
committerjlovell <jlovell@a1ca3aef-8c08-0410-bb20-df032aa958be>
Fri, 4 May 2007 21:17:48 +0000 (21:17 +0000)
git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@321 a1ca3aef-8c08-0410-bb20-df032aa958be

56 files changed:
CHANGES-1.2.txt
CHANGES.txt
Makefile
backend/ipp.c
backend/runloop.c
backend/snmp.c
backend/usb-darwin.c
backend/usb-unix.c
config-scripts/cups-compiler.m4
configure.in
cups/array.c
cups/array.h
cups/auth.c
cups/cups.h
cups/globals.c
cups/globals.h
cups/http-private.h
cups/http.c
cups/ipp-support.c
cups/ipp.h
cups/language.c
cups/localize.c
cups/mark.c
cups/ppd.c
cups/ppd.h
cups/request.c
cups/util.c
doc/help/options.html
doc/help/ref-cupsd-conf.html.in [moved from doc/help/ref-cupsd-conf.html with 98% similarity]
doc/help/ref-snmp-conf.html
doc/help/spec-ipp.html
doc/help/spec-ppd.html
man/cupstestppd.man
packaging/cups.list.in
pdftops/PSOutputDev.cxx
scheduler/client.c
scheduler/client.h
scheduler/conf.c
scheduler/conf.h
scheduler/cups-driverd.c
scheduler/dirsvc.c
scheduler/ipp.c
scheduler/job.c
scheduler/log.c
scheduler/main.c
scheduler/printers.c
systemv/cupstestppd.c
templates/printers.tmpl
test/get-ppd-printer.test [new file with mode: 0644]
test/get-ppd.test [new file with mode: 0644]
test/get-ppds-language.test [new file with mode: 0644]
test/get-ppds-make-and-model.test [new file with mode: 0644]
test/get-ppds-make.test [new file with mode: 0644]
test/get-ppds-product.test [new file with mode: 0644]
test/get-ppds-psversion.test [new file with mode: 0644]
test/ipptest.c

index a6b1ba0d0214a10bb9a1b2368cf79195ad1f3a34..ce6be902bc7563ce37b9cde584590f8b2d4a062b 100644 (file)
@@ -3,6 +3,50 @@ CHANGES-1.2.txt
 
 CHANGES IN CUPS V1.2.11
 
+       - "make distclean" didn't remove all generated files
+         (STR #2366)
+       - Fixed a bug in the advertisement of classes (STR
+         #2373)
+       - The IPP backend now stays running until the job is
+         actually printed by the remote server; previously
+         it would stop monitoring the job if it was held or
+         temporarily stopped (STR #2352)
+        - PDF files were not always printed using the correct
+          orientation (STR #2348)
+        - The scheduler could crash if you specified a bad file:
+          URI for a printer (STR #2351)
+        - The Renew-Subscription operation now returns the
+          notify-lease-duration value that was used (STR #2346)
+        - The IPP backend sent job options to IPP printers,
+          however some printers tried to override the options
+          embedded in the PS/PCL stream with those job options
+          (STR #2349)
+       - ppdLocalize() now also tries a country-specific
+         localization for when localizing to a generic locale
+         name.
+       - The cupstestppd program now allows for partial
+         localizations to reduce the size of universal PPD
+         files.
+       - Chinese PPD files were incorrectly tagged with the
+         "cn" locale (should have been "zh")
+       - The backends now manage the printer-state-reasons
+         attribute more accurately (STR #2345)
+       - Java, PHP, Perl, and Python scripts did not work
+         properly (STR #2342)
+       - The scheduler would take forever to start if the
+         maximum number of file descriptors was set to
+         "unlimited" (STR #2329)
+       - The page-ranges option was incorrectly applied to the
+         banner pages (STR #2336)
+       - Fixed some GCC compile warnings (STR #2340)
+       - The DBUS notification code was broken for older
+         versions of DBUS (STR #2327)
+       - The IPv6 code did not compile on HP-UX 11.23 (STR
+         #2331)
+       - PPD constraints did not work properly with custom
+         options.
+       - Regular PPD options with the name "CustomFoo" did
+         not work.
        - The USB backend did not work on NetBSD (STR #2324)
        - The printer-state-reasons attribute was incorrectly
          cleared after a job completed (STR #2323)
index 45602a84df6244dca41e5325d552231da28bed7c..3985acf684bdfa08d59d9f378553520aa6a147a3 100644 (file)
@@ -1,9 +1,41 @@
-CHANGES.txt - 2007-04-04
+CHANGES.txt - 2007-05-03
 ------------------------
 
 CHANGES IN CUPS V1.3
 
-       - Documentation updates (STR #1775, STR #2130, STR #2131)
+       - Documentation updates (STR #1775, STR #2130, STR #2131,
+         STR #2263, STR #2356)
+       - Added new -R and -W options to the cupstestppd program
+         for greater control over the testing of PPDs.
+       - Added a new cupsGetServerPPD() function for getting
+         an available PPD from the server (STR #2334)
+       - Added a new cupsDoIORequest() function for reading
+         and writing files via IPP requests (STR #2334)
+       - Added a new CUPS_GET_PPD operation for getting an
+         available PPD file on the server (STR #2334) 
+       - CUPS_GET_PPDS now reports multiple ppd-product values
+         if the corresponding PPD contains multiple products
+         (STR #2334)
+       - CUPS_GET_PPDS now reports the PSVersion attributes
+         from a PPD file in the ppd-psversion attribute
+         (STR #2334)
+       - Added a new printer attribute called "cups-version"
+         which reports the version of CUPS that is running
+         (STR #2240)
+       - backendRunLoop() now aborts immediately on SIGTERM
+         if no data has been written yet (STR #2103)
+       - Due to poor IPP support from the vendors, the SNMP
+         backend no longer tries IPP connections; instead,
+         it now uses a lookup file with fallback to port 9100
+         (socket://address) and 515 (lpd://address) printing
+         (STR #2035, STR #2354) 
+       - The scheduler now recreates the CUPS log directory as
+         needed (STR #2353)
+       - cupsLangDefault() now maps new-style Apple locale names
+         to the traditional ll_CC form (STR #2357)
+        - Add new cupsArrayNew2() API to support hashed lookups
+          of array elements (STR #2358)
+        - ppdConflicts() optimizations (STR #2358)
        - The cupstestppd program now tests for existing filters,
          icons, profiles, and dialog extensions (STR #2326)
        - The web interface no longer lists new printers on the
index c24ccdb2d98e4415e1e3c6b2b185ea94640d03ef..1cb72a93227e63e1c5593c5fb55d289198b3ac6d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 #
-# "$Id: Makefile 6332 2007-03-12 16:08:51Z mike $"
+# "$Id: Makefile 6500 2007-04-30 21:47:48Z mike $"
 #
 #   Top-level Makefile for the Common UNIX Printing System (CUPS).
 #
@@ -64,8 +64,10 @@ clean:
 distclean:     clean
        $(RM) Makedefs config.h config.log config.status
        $(RM) cups-config conf/cupsd.conf conf/pam.std
-       $(RM) doc/help/standard.html doc/index.html
+       $(RM) doc/help/ref-cupsd-conf.html doc/help/standard.html
+       $(RM) doc/index.html
        $(RM) init/cups.sh init/cups-lpd
+       $(RM) man/client.conf.man
        $(RM) man/cups-deviced.man man/cups-driverd.man
        $(RM) man/cups-lpd.man man/cupsaddsmb.man man/cupsd.man
        $(RM) man/cupsd.conf.man man/lpoptions.man
@@ -88,6 +90,14 @@ depend:
        done
 
 
+#
+# Generate a ctags file...
+#
+
+ctags:
+       ctags -R .
+
+
 #
 # Install object and target files...
 #
@@ -270,5 +280,5 @@ dist:       all
 
 
 #
-# End of "$Id: Makefile 6332 2007-03-12 16:08:51Z mike $".
+# End of "$Id: Makefile 6500 2007-04-30 21:47:48Z mike $".
 #
index fba56dbfe00e90c96d3e2c8ca5c303238a07194a..2ff1fb823b513784e81030999fc763a34df0d935 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: ipp.c 6434 2007-04-02 22:07:10Z mike $"
+ * "$Id: ipp.c 6482 2007-04-30 17:05:59Z mike $"
  *
  *   IPP backend for the Common UNIX Printing System (CUPS).
  *
@@ -101,6 +101,7 @@ main(int  argc,                             /* I - Number of command-line args */
      char *argv[])                     /* I - Command-line arguments */
 {
   int          i;                      /* Looping var */
+  int          send_options;           /* Send job options? */
   int          num_options;            /* Number of printer options */
   cups_option_t        *options;               /* Printer options */
   char         method[255],            /* Method in URI */
@@ -432,6 +433,8 @@ main(int  argc,                             /* I - Number of command-line args */
     filename  = tmpfilename;
     files     = &filename;
     num_files = 1;
+
+    send_options = 0;
   }
   else
   {
@@ -442,6 +445,8 @@ main(int  argc,                             /* I - Number of command-line args */
     num_files = argc - 6;
     files     = argv + 6;
 
+    send_options = strncasecmp(content_type, "application/vnd.cups-", 21) != 0;
+
 #ifdef HAVE_LIBZ
     if (compression)
       compress_files(num_files, files);
@@ -928,6 +933,7 @@ main(int  argc,                             /* I - Number of command-line args */
        content_type     = "application/postscript";
        copies           = 1;
        copies_remaining = 1;
+        send_options     = 0;
       }
     }
 #endif /* __APPLE__ */
@@ -943,7 +949,7 @@ main(int  argc,                             /* I - Number of command-line args */
                                    num_options, &options);
     }
 
-    if (copies_sup && version > 0)
+    if (copies_sup && version > 0 && send_options)
     {
      /*
       * Only send options if the destination printer supports the copies
@@ -1153,8 +1159,7 @@ main(int  argc,                           /* I - Number of command-line args */
           * Stop polling if the job is finished or pending-held...
          */
 
-          if (job_state->values[0].integer > IPP_JOB_PROCESSING ||
-             job_state->values[0].integer == IPP_JOB_HELD)
+          if (job_state->values[0].integer > IPP_JOB_STOPPED)
          {
            if ((job_sheets = ippFindAttribute(response, 
                                               "job-media-sheets-completed",
@@ -1350,7 +1355,8 @@ compress_files(int  num_files,            /* I - Number of files */
     if ((fd = cupsTempFd(filename, sizeof(filename))) < 0)
     {
       fprintf(stderr,
-              _("ERROR: Unable to create temporary compressed print file: %s\n"),
+              _("ERROR: Unable to create temporary compressed print file: "
+               "%s\n"),
              strerror(errno));
       exit(CUPS_BACKEND_FAILED);
     }
@@ -1761,5 +1767,5 @@ sigterm_handler(int sig)          /* I - Signal */
 
 
 /*
- * End of "$Id: ipp.c 6434 2007-04-02 22:07:10Z mike $".
+ * End of "$Id: ipp.c 6482 2007-04-30 17:05:59Z mike $".
  */
index dc2890a89997cc39873cb1b6571dca57cc4a8905..fd0bb8f0499ac6b5b71518dd7bcbafa1e5678841 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: runloop.c 6403 2007-03-27 16:00:56Z mike $"
+ * "$Id: runloop.c 6498 2007-04-30 21:40:33Z mike $"
  *
  *   Common run loop API for the Common UNIX Printing System (CUPS).
  *
@@ -104,7 +104,8 @@ backendRunLoop(
   * Now loop until we are out of data from print_fd...
   */
 
-  for (print_bytes = 0, print_ptr = print_buffer, offline = 0, paperout = 0, total_bytes = 0;;)
+  for (print_bytes = 0, print_ptr = print_buffer, offline = -1,
+           paperout = -1, total_bytes = 0;;)
   {
    /*
     * Use select() to determine whether we have data to copy around...
@@ -130,12 +131,18 @@ backendRunLoop(
        * Pause printing to clear any pending errors...
        */
 
-       if (errno == ENXIO && !offline)
+       if (errno == ENXIO && offline != 1)
        {
          fputs("STATE: +offline-error\n", stderr);
          fputs(_("INFO: Printer is currently off-line.\n"), stderr);
          offline = 1;
        }
+       else if (errno == EINTR && total_bytes == 0)
+       {
+         fputs("DEBUG: Received an interrupt before any bytes were "
+               "written, aborting!\n", stderr);
+          return (0);
+       }
 
        sleep(1);
        continue;
@@ -215,7 +222,7 @@ backendRunLoop(
 
         if (errno == ENOSPC)
        {
-         if (!paperout)
+         if (paperout != 1)
          {
            fputs("STATE: +media-empty-error\n", stderr);
            fputs(_("ERROR: Out of paper!\n"), stderr);
@@ -224,7 +231,7 @@ backendRunLoop(
         }
        else if (errno == ENXIO)
        {
-         if (!offline)
+         if (offline != 1)
          {
            fputs("STATE: +offline-error\n", stderr);
            fputs(_("INFO: Printer is currently off-line.\n"), stderr);
@@ -271,5 +278,5 @@ backendRunLoop(
 
 
 /*
- * End of "$Id: runloop.c 6403 2007-03-27 16:00:56Z mike $".
+ * End of "$Id: runloop.c 6498 2007-04-30 21:40:33Z mike $".
  */
index 0298ee9dbfa6f9e21fead2be68a4ee6d28ef3779..bcacf14c15c210fdd4dd53b41b21fe97e8297674 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: snmp.c 6403 2007-03-27 16:00:56Z mike $"
+ * "$Id: snmp.c 6495 2007-04-30 21:23:04Z mike $"
  *
  *   SNMP discovery backend for the Common UNIX Printing System (CUPS).
  *
@@ -28,6 +28,7 @@
  *   main()                    - Discover printers via SNMP.
  *   add_array()               - Add a string to an array.
  *   add_cache()               - Add a cached device...
+ *   add_device_uri()          - Add a device URI to the cache.
  *   alarm_handler()           - Handle alarm signals...
  *   asn1_decode_snmp()        - Decode a SNMP packet.
  *   asn1_debug()              - Decode an ASN1-encoded message.
@@ -52,7 +53,6 @@
  *                               packed integer value.
  *   compare_cache()           - Compare two cache entries.
  *   debug_printf()            - Display some debugging information.
- *   do_request()              - Do a non-blocking IPP request.
  *   fix_make_model()          - Fix common problems in the make-and-model
  *                               string.
  *   free_array()              - Free an array of strings.
 #include "backend-private.h"
 #include <cups/array.h>
 #include <cups/file.h>
+#include <regex.h>
 
 
 /*
  * This backend implements SNMP printer discovery.  It uses a broadcast-
- * based approach to get SNMP response packets from potential printers
- * and then interrogates each responder by trying to connect on port
- * 631, 9100, and 515.
+ * based approach to get SNMP response packets from potential printers,
+ * tries a mDNS lookup (Mac OS X only at present), a URI lookup based on
+ * the device description string, and finally a probe of port 9100
+ * (AppSocket) and 515 (LPD).
  *
  * The current focus is on printers with internal network cards, although
  * the code also works with many external print servers as well.  Future
  *     Address @IF(name)
  *     Community name
  *     DebugLevel N
+ *     DeviceURI "regex pattern" uri
  *     HostNameLookups on
  *     HostNameLookups off
+ *     MaxRunTime N
  *
  * The default is to use:
  *
  *     Community public
  *     DebugLevel 0
  *     HostNameLookups off
+ *     MaxRunTime 10
  *
  * This backend is known to work with the following network printers and
  * print servers:
  * Types...
  */
 
+typedef struct device_uri_s            /**** DeviceURI values ****/
+{
+  regex_t      re;                     /* Regular expression to match */
+  cups_array_t *uris;                  /* URIs */
+} device_uri_t;
+
 typedef struct snmp_cache_s            /**** SNMP scan cache ****/
 {
   http_addr_t  address;                /* Address of device */
@@ -209,6 +220,7 @@ static char         *add_array(cups_array_t *a, const char *s);
 static void            add_cache(http_addr_t *addr, const char *addrname,
                                  const char *uri, const char *id,
                                  const char *make_and_model);
+static device_uri_t    *add_device_uri(char *value);
 static void            alarm_handler(int sig);
 static int             asn1_decode_snmp(unsigned char *buffer, size_t len,
                                         snmp_packet_t *packet);
@@ -246,8 +258,6 @@ static int          asn1_size_oid(const int *oid);
 static int             asn1_size_packed(int integer);
 static int             compare_cache(snmp_cache_t *a, snmp_cache_t *b);
 static void            debug_printf(const char *format, ...);
-static ipp_t           *do_request(http_t *http, ipp_t *request,
-                                   const char *resource);
 static void            fix_make_model(char *make_model,
                                       const char *old_make_model,
                                       int make_model_size);
@@ -281,12 +291,13 @@ static cups_array_t       *Addresses = NULL;
 static cups_array_t    *Communities = NULL;
 static cups_array_t    *Devices = NULL;
 static int             DebugLevel = 0;
-static int             DeviceTypeOID[] = { 1, 3, 6, 1, 2, 1, 25, 3,
-                                           2, 1, 2, 1, 0 };
 static int             DeviceDescOID[] = { 1, 3, 6, 1, 2, 1, 25, 3,
                                            2, 1, 3, 1, 0 };
-static unsigned                DeviceTypeRequest;
 static unsigned                DeviceDescRequest;
+static int             DeviceTypeOID[] = { 1, 3, 6, 1, 2, 1, 25, 3,
+                                           2, 1, 2, 1, 0 };
+static unsigned                DeviceTypeRequest;
+static cups_array_t    *DeviceURIs = NULL;
 static int             HostNameLookups = 0;
 static int             MaxRunTime = 10;
 static struct timeval  StartTime;
@@ -433,6 +444,96 @@ add_cache(http_addr_t *addr,               /* I - Device IP address */
 }
 
 
+/*
+ * 'add_device_uri()' - Add a device URI to the cache.
+ *
+ * The value string is modified (chopped up) as needed.
+ */
+
+static device_uri_t *                  /* O - Device URI */
+add_device_uri(char *value)            /* I - Value from snmp.conf */
+{
+  device_uri_t *device_uri;            /* Device URI */
+  char         *start;                 /* Start of value */
+
+
+ /*
+  * Allocate memory as needed...
+  */
+
+  if (!DeviceURIs)
+    DeviceURIs = cupsArrayNew(NULL, NULL);
+
+  if (!DeviceURIs)
+    return (NULL);
+
+  if ((device_uri = calloc(1, sizeof(device_uri_t))) == NULL)
+    return (NULL);
+
+  if ((device_uri->uris = cupsArrayNew(NULL, NULL)) == NULL)
+  {
+    free(device_uri);
+    return (NULL);
+  }
+
+ /*
+  * Scan the value string for the regular expression and URI(s)...
+  */
+
+  value ++; /* Skip leading " */
+
+  for (start = value; *value && *value != '\"'; value ++)
+    if (*value == '\\' && value[1])
+      _cups_strcpy(value, value + 1);
+
+  if (!*value)
+  {
+    fputs("ERROR: Missing end quote for DeviceURI!\n", stderr);
+
+    cupsArrayDelete(device_uri->uris);
+    free(device_uri);
+
+    return (NULL);
+  }
+
+  *value++ = '\0';
+
+  if (regcomp(&(device_uri->re), start, REG_EXTENDED | REG_ICASE))
+  {
+    fputs("ERROR: Bad regular expression for DeviceURI!\n", stderr);
+
+    cupsArrayDelete(device_uri->uris);
+    free(device_uri);
+
+    return (NULL);
+  }
+
+  while (*value)
+  {
+    while (isspace(*value & 255))
+      value ++;
+
+    if (!*value)
+      break;
+
+    for (start = value; *value && !isspace(*value & 255); value ++);
+
+    if (*value)
+      *value++ = '\0';
+
+    cupsArrayAdd(device_uri->uris, strdup(start));
+  }
+
+ /*
+  * Add the device URI to the list and return it...
+  */
+
+  cupsArrayAdd(DeviceURIs, device_uri);
+
+  return (device_uri);
+}
+
+
 /*
  * 'alarm_handler()' - Handle alarm signals...
  */
@@ -1259,173 +1360,6 @@ debug_printf(const char *format,        /* I - Printf-style format string */
 }
 
 
-/*
- * 'do_request()' - Do a non-blocking IPP request.
- */
-
-static ipp_t *                         /* O - Response data or NULL */
-do_request(http_t     *http,           /* I - HTTP connection to server */
-           ipp_t      *request,                /* I - IPP request */
-           const char *resource)       /* I - HTTP resource for POST */
-{
-  ipp_t                *response;              /* IPP response data */
-  http_status_t        status;                 /* Status of HTTP request */
-  ipp_state_t  state;                  /* State of IPP processing */
-
-
- /*
-  * Setup the HTTP variables needed...
-  */
-
-  httpClearFields(http);
-  httpSetLength(http, ippLength(request));
-  httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp");
-
- /*
-  * Do the POST request...
-  */
-
-  debug_printf("DEBUG: %.3f POST %s...\n", run_time(), resource);
-
-  if (httpPost(http, resource))
-  {
-    if (httpReconnect(http))
-    {
-      _cupsSetError(IPP_DEVICE_ERROR, "Unable to reconnect");
-      return (NULL);
-    }
-    else if (httpPost(http, resource))
-    {
-      _cupsSetError(IPP_GONE, "Unable to POST");
-      return (NULL);
-    }
-  }
-
- /*
-  * Send the IPP data...
-  */
-
-  request->state = IPP_IDLE;
-  status         = HTTP_CONTINUE;
-
-  while ((state = ippWrite(http, request)) != IPP_DATA)
-    if (state == IPP_ERROR)
-    {
-      status = HTTP_ERROR;
-      break;
-    }
-    else if (httpCheck(http))
-    {
-      if ((status = httpUpdate(http)) != HTTP_CONTINUE)
-       break;
-    }
-
- /*
-  * Get the server's return status...
-  */
-
-  debug_printf("DEBUG: %.3f Getting response...\n", run_time());
-
-  while (status == HTTP_CONTINUE)
-    if (httpWait(http, 1000))
-      status = httpUpdate(http);
-    else
-    {
-      status      = HTTP_ERROR;
-      http->error = ETIMEDOUT;
-    }
-
-  if (status != HTTP_OK)
-  {
-   /*
-    * Flush any error message...
-    */
-
-    httpFlush(http);
-    response = NULL;
-  }
-  else
-  {
-   /*
-    * Read the response...
-    */
-
-    response = ippNew();
-
-    while ((state = ippRead(http, response)) != IPP_DATA)
-      if (state == IPP_ERROR)
-      {
-       /*
-        * Delete the response...
-       */
-
-       ippDelete(response);
-       response = NULL;
-
-        _cupsSetError(IPP_SERVICE_UNAVAILABLE, strerror(errno));
-       break;
-      }
-  }
-
- /*
-  * Delete the original request and return the response...
-  */
-  
-  ippDelete(request);
-
-  if (response)
-  {
-    ipp_attribute_t    *attr;          /* status-message attribute */
-
-
-    attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT);
-
-    _cupsSetError(response->request.status.status_code,
-                   attr ? attr->values[0].string.text :
-                      ippErrorString(response->request.status.status_code));
-  }
-  else if (status != HTTP_OK)
-  {
-    switch (status)
-    {
-      case HTTP_NOT_FOUND :
-          _cupsSetError(IPP_NOT_FOUND, httpStatus(status));
-         break;
-
-      case HTTP_UNAUTHORIZED :
-          _cupsSetError(IPP_NOT_AUTHORIZED, httpStatus(status));
-         break;
-
-      case HTTP_FORBIDDEN :
-          _cupsSetError(IPP_FORBIDDEN, httpStatus(status));
-         break;
-
-      case HTTP_BAD_REQUEST :
-          _cupsSetError(IPP_BAD_REQUEST, httpStatus(status));
-         break;
-
-      case HTTP_REQUEST_TOO_LARGE :
-          _cupsSetError(IPP_REQUEST_VALUE, httpStatus(status));
-         break;
-
-      case HTTP_NOT_IMPLEMENTED :
-          _cupsSetError(IPP_OPERATION_NOT_SUPPORTED, httpStatus(status));
-         break;
-
-      case HTTP_NOT_SUPPORTED :
-          _cupsSetError(IPP_VERSION_NOT_SUPPORTED, httpStatus(status));
-         break;
-
-      default :
-         _cupsSetError(IPP_SERVICE_UNAVAILABLE, httpStatus(status));
-         break;
-    }
-  }
-
-  return (response);
-}
-
-
 /*
  * 'fix_make_model()' - Fix common problems in the make-and-model string.
  */
@@ -1718,216 +1652,67 @@ password_cb(const char *prompt)                /* I - Prompt message */
 static void
 probe_device(snmp_cache_t *device)     /* I - Device */
 {
-  int          i, j;                   /* Looping vars */
-  http_t       *http;                  /* HTTP connection for IPP */
-  char         uri[1024];              /* Full device URI */
+  char         uri[1024],              /* Full device URI */
+               *uriptr,                /* Pointer into URI */
+               *format;                /* Format string for device */
+  device_uri_t *device_uri;            /* Current DeviceURI match */
 
 
- /*
-  * Try connecting via IPP first...
-  */
-
   debug_printf("DEBUG: %.3f Probing %s...\n", run_time(), device->addrname);
 
-  if (device->make_and_model &&
-      (!strncasecmp(device->make_and_model, "Epson", 5) ||
-       !strncasecmp(device->make_and_model, "HP ", 3) ||
-       !strncasecmp(device->make_and_model, "Hewlett", 7) ||
-       !strncasecmp(device->make_and_model, "Kyocera", 7) ||
-       !strncasecmp(device->make_and_model, "Lexmark", 7) ||
-       !strncasecmp(device->make_and_model, "Tektronix", 9) ||
-       !strncasecmp(device->make_and_model, "Xerox", 5)))
-  {
-   /*
-    * Epson, HP, Kyocera, Lexmark, Tektronix, and Xerox printers often lock
-    * up on IPP probes, so exclude them from the IPP connection test...
-    */
+#ifdef __APPLE__
+ /*
+  * TODO: Try an mDNS query first, and then fallback on direct probes...
+  */
 
-    http = NULL;
-  }
-  else
+  if (!try_connect(&(device->address), device->addrname, 5353))
   {
-   /*
-    * Otherwise, try connecting for up to 1 second...
-    */
-
-    alarm(1);
-    http = httpConnect(device->addrname, 631);
-    alarm(0);
+    debug_printf("DEBUG: %s supports mDNS, not reporting!\n", device->addrname);
+    return;
   }
+#endif /* __APPLE__ */
 
-  if (http)
-  {
-   /*
-    * IPP is supported...
-    */
-
-    ipp_t              *request,       /* IPP request */
-                       *response;      /* IPP response */
-    ipp_attribute_t    *model,         /* printer-make-and-model attribute */
-                       *info,          /* printer-info attribute */
-                       *supported;     /* printer-uri-supported attribute */
-    char               make_model[256],/* Make and model string to use */
-                       temp[256];      /* Temporary make/model string */
-    int                        num_uris;       /* Number of good URIs */
-    static const char * const resources[] =
-                       {               /* Common resource paths for IPP */
-                         "/ipp",
-                         /*"/ipp/port2",*/
-                         /*"/ipp/port3",*/
-                         /*"/EPSON_IPP_Printer",*/
-                         "/LPT1",
-                         "/LPT2",
-                         "/COM1",
-                         "/"
-                       };
-
-
-   /*
-    * Use non-blocking IO...
-    */
-
-    httpBlocking(http, 0);
-
-   /*
-    * Loop through a list of common resources that covers 99% of the
-    * IPP-capable printers on the market today...
-    */
+ /*
+  * Lookup the device in the match table...
+  */
 
-    for (i = 0, num_uris = 0;
-         i < (int)(sizeof(resources) / sizeof(resources[0]));
-         i ++)
+  for (device_uri = (device_uri_t *)cupsArrayFirst(DeviceURIs);
+       device_uri;
+       device_uri = (device_uri_t *)cupsArrayNext(DeviceURIs))
+    if (!regexec(&(device_uri->re), device->make_and_model, 0, NULL, 0))
     {
      /*
-      * Stop early if we are out of time...
-      */
-
-      if (MaxRunTime > 0 && run_time() >= MaxRunTime)
-        break;
-
-     /*
-      * Don't look past /ipp if we have found a working URI...
+      * Found a match, add the URIs...
       */
 
-      if (num_uris > 0 && strncmp(resources[i], "/ipp", 4))
-        break;
-
-      httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
-                      device->addrname, 631, resources[i]);
-
-      request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES);
-
-      ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
-                   NULL, uri);
-
-      response = do_request(http, request, resources[i]);
-
-      debug_printf("DEBUG: %.3f %s %s (%s)\n", run_time(), uri,
-                  ippErrorString(cupsLastError()), cupsLastErrorString());
-
-      if (response && response->request.status.status_code == IPP_OK)
+      for (format = (char *)cupsArrayFirst(device_uri->uris);
+           format;
+          format = (char *)cupsArrayNext(device_uri->uris))
       {
-        model     = ippFindAttribute(response, "printer-make-and-model",
-                                    IPP_TAG_TEXT);
-        info      = ippFindAttribute(response, "printer-info", IPP_TAG_TEXT);
-        supported = ippFindAttribute(response, "printer-uri-supported",
-                                    IPP_TAG_URI);
-
-        if (!supported)
-       {
-         fprintf(stderr, "ERROR: Missing printer-uri-supported from %s!\n",
-                 device->addrname);
-
-         httpClose(http);
-         return;
-       }
-
-        debug_printf("DEBUG: printer-info=\"%s\"\n",
-                    info ? info->values[0].string.text : "(null)");
-        debug_printf("DEBUG: printer-make-and-model=\"%s\"\n",
-                    model ? model->values[0].string.text : "(null)");
-
-       /*
-        * Don't advertise this port if the printer actually only supports
-       * a more generic version...
-       */
-
-        if (!strncmp(resources[i], "/ipp/", 5))
-       {
-         for (j = 0; j < supported->num_values; j ++)
-           if (strstr(supported->values[j].string.text, "/ipp/"))
-             break;
-
-         if (j >= supported->num_values)
+        for (uriptr = uri; *format && uriptr < (uri + sizeof(uri) - 1);)
+         if (*format == '%' && format[1] == 's')
          {
-           ippDelete(response);
-           break;
-         }
-        }
-
-       /*
-        * Don't use the printer-info attribute if it does not contain the
-       * IEEE-1284 device ID data...
-       */
-
-        if (info &&
-           (!strchr(info->values[0].string.text, ':') ||
-            !strchr(info->values[0].string.text, ';')))
-         info = NULL;
-
-       /*
-        * Don't use the printer-make-and-model if it contains a generic
-       * string like "Ricoh IPP Printer"...
-       */
-
-       if (model && strstr(model->values[0].string.text, "IPP Printer"))
-         model = NULL;
-
-       /*
-        * If we don't have a printer-make-and-model string from the printer
-       * but do have the 1284 device ID string, generate a make-and-model
-       * string from the device ID info...
-       */
-
-       if (model)
-          strlcpy(temp, model->values[0].string.text, sizeof(temp));
-       else if (info)
-         backendGetMakeModel(info->values[0].string.text, temp, sizeof(temp));
-        else
-         temp[0] = '\0';
-
-        fix_make_model(make_model, temp, sizeof(make_model));
+          /*
+           * Insert hostname/address...
+           */
 
-       /*
-        * Update the current device or add a new printer to the cache...
-       */
+           strlcpy(uriptr, device->addrname, sizeof(uri) - (uriptr - uri));
+           uriptr += strlen(uriptr);
+           format += 2;
+         }
+         else
+           *uriptr++ = *format++;
 
-        if (num_uris == 0)
-         update_cache(device, uri, 
-                      info ? info->values[0].string.text : NULL,
-                      make_model[0] ? make_model : NULL);
-       else
-          add_cache(&(device->address), device->addrname, uri,
-                   info ? info->values[0].string.text : NULL,
-                   make_model[0] ? make_model : NULL);
+        *uriptr = '\0';
 
-        num_uris ++;
+        update_cache(device, uri, NULL, NULL);
       }
 
-      ippDelete(response);
-
-      if (num_uris > 0 && cupsLastError() != IPP_OK)
-        break;
-    }
-
-    httpClose(http);
-
-    if (num_uris > 0)
       return;
-  }
+    }
 
  /*
-  * OK, now try the standard ports...
+  * Then try the standard ports...
   */
 
   if (!try_connect(&(device->address), device->addrname, 9100))
@@ -2011,6 +1796,15 @@ read_snmp_conf(const char *address)      /* I - Single address to probe */
         add_array(Communities, value);
       else if (!strcasecmp(line, "DebugLevel"))
         DebugLevel = atoi(value);
+      else if (!strcasecmp(line, "DeviceURI"))
+      {
+        if (*value != '\"')
+         fprintf(stderr,
+                 "ERROR: Missing double quote for regular expression on "
+                 "line %d of %s!\n", linenum, filename);
+        else
+         add_device_uri(value);
+      }
       else if (!strcasecmp(line, "HostNameLookups"))
         HostNameLookups = !strcasecmp(value, "on") ||
                          !strcasecmp(value, "yes") ||
@@ -2461,5 +2255,5 @@ update_cache(snmp_cache_t *device,        /* I - Device */
 
 
 /*
- * End of "$Id: snmp.c 6403 2007-03-27 16:00:56Z mike $".
+ * End of "$Id: snmp.c 6495 2007-04-30 21:23:04Z mike $".
  */
index d1407696171c59dd76850a20fe7b9d749ec94db4..4cde9129ca807f04da63bfb453571eae37b26196 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: usb-darwin.c 6432 2007-04-02 21:50:28Z mike $"
+ * "$Id: usb-darwin.c 6491 2007-04-30 18:21:52Z mike $"
  *
  * Copyright Â© 2005-2007 Apple Inc. All rights reserved.
  *
@@ -598,16 +598,6 @@ static Boolean list_device_callback(void *refcon, io_service_t obj)
       else
         strcpy(modelstr + 1, "Printer");
 
-     /*
-      * Fix common HP 1284 bug...
-      */
-
-      if (!strcasecmp(makestr, "Hewlett-Packard"))
-        strcpy(makestr, "HP");
-
-      if (!strncasecmp(modelstr + 1, "hp ", 3))
-        _cups_strcpy(modelstr + 1, modelstr + 4);
-
       optionsstr[0] = '\0';
       if (serial != NULL)
       {
@@ -622,6 +612,16 @@ static Boolean list_device_callback(void *refcon, io_service_t obj)
       httpAssembleURI(HTTP_URI_CODING_ALL, uristr, sizeof(uristr), "usb", NULL, makestr, 0, modelstr);
       strncat(uristr, optionsstr, sizeof(uristr));
 
+     /*
+      * Fix common HP 1284 bug...
+      */
+
+      if (!strcasecmp(makestr, "Hewlett-Packard"))
+        strcpy(makestr, "HP");
+
+      if (!strncasecmp(modelstr + 1, "hp ", 3))
+        _cups_strcpy(modelstr + 1, modelstr + 4);
+
       printf("direct %s \"%s %s\" \"%s %s USB\" \"%s\"\n", uristr, makestr,
              &modelstr[1], makestr, &modelstr[1], idstr);
 
@@ -654,7 +654,7 @@ static Boolean find_device_callback(void *refcon, io_service_t obj)
       copy_deviceinfo(idString, &make, &model, &serial);
       if (CFStringCompare(make, userData->make, kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
        if (CFStringCompare(model, userData->model, kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
-         if (userData->serial != NULL) {
+         if (userData->serial != NULL && CFStringGetLength(userData->serial) > 0 ) {
            if (serial != NULL && CFStringCompare(serial, userData->serial, kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
              IOObjectRetain(obj);
              userData->printerObj = obj;
@@ -1729,5 +1729,5 @@ static void usbGetDevState(printer_data_t *userData, cups_sc_status_t *status, c
 }
 
 /*
- * End of "$Id: usb-darwin.c 6432 2007-04-02 21:50:28Z mike $".
+ * End of "$Id: usb-darwin.c 6491 2007-04-30 18:21:52Z mike $".
  */
index feddc046a9e991f57c66fe2816a3908ef084781a..477fee2f68eb51d3b690836c3a0ae701e2ff73e3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: usb-unix.c 6437 2007-04-03 17:38:10Z mike $"
+ * "$Id: usb-unix.c 6510 2007-05-04 13:08:05Z mike $"
  *
  *   USB port backend for the Common UNIX Printing System (CUPS).
  *
@@ -80,10 +80,11 @@ print_device(const char *uri,               /* I - Device URI */
 
   do
   {
-#ifdef __NetBSD__
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
    /*
-    * NetBSD's ulpt driver currently does not support the
-    * back-channel...
+    * *BSD's ulpt driver currently does not support the
+    * back-channel, incorrectly returns data ready on a select(),
+    * and locks up on read()...
     */
 
     use_bc = 0;
@@ -100,7 +101,7 @@ print_device(const char *uri,               /* I - Device URI */
              strcasecmp(hostname, "Canon") &&
              strcasecmp(hostname, "Konica Minolta") &&
              strcasecmp(hostname, "Minolta");
-#endif /* __NetBSD__ */
+#endif /* __FreeBSD__ || __NetBSD__ || __OpenBSD__ || __DragonFly__ */
 
     if ((device_fd = open_device(uri, &use_bc)) == -1)
     {
@@ -617,5 +618,5 @@ side_cb(int print_fd,                       /* I - Print file */
 
 
 /*
- * End of "$Id: usb-unix.c 6437 2007-04-03 17:38:10Z mike $".
+ * End of "$Id: usb-unix.c 6510 2007-05-04 13:08:05Z mike $".
  */
index 1af623a1634e0aaed535f9b030d4c34195185253..e2e0585e4f1364c36acbd088b7c2d54ea29151be 100644 (file)
@@ -1,5 +1,5 @@
 dnl
-dnl "$Id: cups-compiler.m4 6264 2007-02-11 17:11:15Z mike $"
+dnl "$Id: cups-compiler.m4 6447 2007-04-10 18:02:00Z mike $"
 dnl
 dnl   Compiler stuff for the Common UNIX Printing System (CUPS).
 dnl
@@ -435,6 +435,10 @@ case $uname in
                # HP-UX 11.00 (at least) needs this definition to get the
                # u_short type used by the IP headers...
                OPTIM="$OPTIM -D_INCLUDE_HPUX_SOURCE"
+
+               # HP-UX 11.23 (at least) needs this definition to get the
+               # IPv6 header to work...
+               OPTIM="$OPTIM -D_HPUX_SOURCE"
                ;;
 
        OSF*)
@@ -445,5 +449,5 @@ case $uname in
 esac
 
 dnl
-dnl End of "$Id: cups-compiler.m4 6264 2007-02-11 17:11:15Z mike $".
+dnl End of "$Id: cups-compiler.m4 6447 2007-04-10 18:02:00Z mike $".
 dnl
index 2472ce6fc83f3f7c0a958886f6cf456836fc9769..0850d8d2362a07f85dd8f030af6d148670ff2fb7 100644 (file)
@@ -1,5 +1,5 @@
 dnl
-dnl "$Id: configure.in 6291 2007-02-19 21:54:27Z mike $"
+dnl "$Id: configure.in 6488 2007-04-30 17:45:57Z mike $"
 dnl
 dnl   Configuration script for the Common UNIX Printing System (CUPS).
 dnl
@@ -77,8 +77,8 @@ AC_SUBST(UNINSTALL_LANGUAGES)
 
 AC_OUTPUT(Makedefs packaging/cups.list init/cups.sh init/cups-lpd cups-config
          conf/cupsd.conf conf/pam.std doc/index.html
-         doc/help/standard.html man/client.conf.man
-         man/cups-deviced.man man/cups-driverd.man
+         doc/help/ref-cupsd-conf.html doc/help/standard.html
+         man/client.conf.man man/cups-deviced.man man/cups-driverd.man
          man/cups-lpd.man man/cupsaddsmb.man man/cupsd.man
          man/cupsd.conf.man man/lpoptions.man
          templates/edit-config.tmpl templates/header.tmpl
@@ -87,5 +87,5 @@ AC_OUTPUT(Makedefs packaging/cups.list init/cups.sh init/cups-lpd cups-config
 chmod +x cups-config
 
 dnl
-dnl End of "$Id: configure.in 6291 2007-02-19 21:54:27Z mike $".
+dnl End of "$Id: configure.in 6488 2007-04-30 17:45:57Z mike $".
 dnl
index b792c465c5c9d8a14cd66a4885d3537197756e60..50223a5aea8cea7c67a87090cf5cd20f827e1957 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * "$Id: array.c 6123 2006-11-21 15:36:04Z mike $"
+ * "$Id: array.c 6477 2007-04-25 19:55:45Z mike $"
  *
  *   Sorted array routines for the Common UNIX Printing System (CUPS).
  *
- *   Copyright 1997-2006 by Easy Software Products.
+ *   Copyright 1997-2007 by Easy Software Products.
  *
  *   These coded instructions, statements, and computer programs are the
  *   property of Easy Software Products and are protected by Federal
@@ -90,6 +90,9 @@ struct _cups_array_s                  /**** CUPS array structure ****/
   void                 **elements;     /* Array elements */
   cups_array_func_t    compare;        /* Element comparison function */
   void                 *data;          /* User data passed to compare */
+  cups_ahash_func_t    hashfunc;       /* Hash function */
+  int                  hashsize,       /* Size of hash */
+                       *hash;          /* Hash array */
 };
 
 
@@ -229,6 +232,9 @@ cupsArrayDelete(cups_array_t *a)    /* I - Array */
   if (a->alloc_elements)
     free(a->elements);
 
+  if (a->hashsize)
+    free(a->hash);
+
   free(a);
 }
 
@@ -306,7 +312,8 @@ cupsArrayFind(cups_array_t *a,              /* I - Array */
               void         *e)         /* I - Element */
 {
   int  current,                        /* Current element */
-       diff;                           /* Difference */
+       diff,                           /* Difference */
+       hash;                           /* Hash index */
 
 
  /*
@@ -327,7 +334,30 @@ cupsArrayFind(cups_array_t *a,             /* I - Array */
   * Yes, look for a match...
   */
 
-  current = cups_array_find(a, e, a->current, &diff);
+  if (a->hash)
+  {
+    hash = (*(a->hashfunc))(e, a->data);
+
+    if (hash < 0 || hash >= a->hashsize)
+    {
+      current = a->current;
+      hash    = -1;
+    }
+    else
+    {
+      current = a->hash[hash];
+
+      if (current < 0 || current >= a->num_elements)
+        current = a->current;
+    }
+  }
+  else
+  {
+    current = a->current;
+    hash    = -1;
+  }
+
+  current = cups_array_find(a, e, current, &diff);
   if (!diff)
   {
    /*
@@ -348,6 +378,9 @@ cupsArrayFind(cups_array_t *a,              /* I - Array */
 
     a->current = current;
 
+    if (hash >= 0)
+      a->hash[hash] = current;
+
     return (a->elements[current]);
   }
   else
@@ -499,6 +532,22 @@ cupsArrayLast(cups_array_t *a)             /* I - Array */
 cups_array_t *                         /* O - Array */
 cupsArrayNew(cups_array_func_t f,      /* I - Comparison function */
              void              *d)     /* I - User data */
+{
+  return (cupsArrayNew2(f, d, 0, 0));
+}
+
+
+/*
+ * 'cupsArrayNew2()' - Create a new array with hash.
+ *
+ * @since CUPS 1.3@
+ */
+
+cups_array_t *                         /* O - Array */
+cupsArrayNew2(cups_array_func_t  f,    /* I - Comparison function */
+              void               *d,   /* I - User data */
+              cups_ahash_func_t  h,    /* I - Hash function*/
+             int                hsize) /* I - Hash size */
 {
   cups_array_t *a;                     /* Array  */
 
@@ -518,6 +567,21 @@ cupsArrayNew(cups_array_func_t f,  /* I - Comparison function */
   a->num_saved = 0;
   a->unique    = 1;
 
+  if (hsize > 0 && h)
+  {
+    a->hashfunc  = h;
+    a->hashsize  = hsize;
+    a->hash      = malloc(hsize * sizeof(int));
+
+    if (!a->hash)
+    {
+      free(a);
+      return (NULL);
+    }
+
+    memset(a->hash, -1, hsize * sizeof(int));
+  }
+
   return (a);
 }
 
@@ -998,5 +1062,5 @@ cups_array_find(cups_array_t *a,   /* I - Array */
 
 
 /*
- * End of "$Id: array.c 6123 2006-11-21 15:36:04Z mike $".
+ * End of "$Id: array.c 6477 2007-04-25 19:55:45Z mike $".
  */
index 6756a100a349b3aff3e5c0919941dcfff906f8b5..47d28b93089f60c31dce984665cb7b96577d3f32 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * "$Id: array.h 6123 2006-11-21 15:36:04Z mike $"
+ * "$Id: array.h 6477 2007-04-25 19:55:45Z mike $"
  *
  *   Sorted array definitions for the Common UNIX Printing System (CUPS).
  *
- *   Copyright 1997-2006 by Easy Software Products.
+ *   Copyright 1997-2007 by Easy Software Products.
  *
  *   These coded instructions, statements, and computer programs are the
  *   property of Easy Software Products and are protected by Federal
@@ -51,6 +51,9 @@ typedef struct _cups_array_s cups_array_t;
                                        /**** CUPS array type ****/
 typedef int (*cups_array_func_t)(void *first, void *second, void *data);
                                        /**** Array comparison function ****/
+typedef int (*cups_ahash_func_t)(void *element, void *data);
+                                       /**** Array hash function ****/
+
 
 /*
  * Functions...
@@ -70,6 +73,8 @@ extern void           *cupsArrayIndex(cups_array_t *a, int n);
 extern int             cupsArrayInsert(cups_array_t *a, void *e);
 extern void            *cupsArrayLast(cups_array_t *a);
 extern cups_array_t    *cupsArrayNew(cups_array_func_t f, void *d);
+extern cups_array_t    *cupsArrayNew2(cups_array_func_t f, void *d,
+                                      cups_ahash_func_t h, int hsize);
 extern void            *cupsArrayNext(cups_array_t *a);
 extern void            *cupsArrayPrev(cups_array_t *a);
 extern int             cupsArrayRemove(cups_array_t *a, void *e);
@@ -83,5 +88,5 @@ extern void           *cupsArrayUserData(cups_array_t *a);
 #endif /* !_CUPS_ARRAY_H_ */
 
 /*
- * End of "$Id: array.h 6123 2006-11-21 15:36:04Z mike $".
+ * End of "$Id: array.h 6477 2007-04-25 19:55:45Z mike $".
  */
index 1ee0476f2590c20255f768ca87aaa0a8b471469d..7a3f324c9e0b192c2fcb414a2c28cec399f91c5c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: auth.c 6397 2007-03-25 23:33:32Z mike $"
+ * "$Id: auth.c 6499 2007-04-30 21:44:43Z mike $"
  *
  *   Authentication functions for the Common UNIX Printing System (CUPS).
  *
@@ -468,17 +468,17 @@ cups_local_auth(http_t *http)             /* I - HTTP connection to server */
   * Delete any previous authorization reference...
   */
   
-  if (cg->auth_ref)
+  if (http->auth_ref)
   {
-    AuthorizationFree(cg->auth_ref, kAuthorizationFlagDefaults);
-    cg->auth_ref = NULL;
+    AuthorizationFree(http->auth_ref, kAuthorizationFlagDefaults);
+    http->auth_ref = NULL;
   }
 
   if (httpGetSubField2(http, HTTP_FIELD_WWW_AUTHENTICATE, "authkey", 
                       auth_key, sizeof(auth_key)))
   {
     status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, 
-                                kAuthorizationFlagDefaults, &cg->auth_ref);
+                                kAuthorizationFlagDefaults, &http->auth_ref);
     if (status != errAuthorizationSuccess)
     {
       DEBUG_printf(("cups_local_auth: AuthorizationCreate() returned %d (%s)\n",
@@ -499,11 +499,11 @@ cups_local_auth(http_t *http)             /* I - HTTP connection to server */
                 kAuthorizationFlagInteractionAllowed | 
                 kAuthorizationFlagExtendRights;
 
-    status = AuthorizationCopyRights(cg->auth_ref, &auth_rights, 
+    status = AuthorizationCopyRights(http->auth_ref, &auth_rights, 
                                     kAuthorizationEmptyEnvironment, 
                                     auth_flags, NULL);
     if (status == errAuthorizationSuccess)
-      status = AuthorizationMakeExternalForm(cg->auth_ref, &auth_extrn);
+      status = AuthorizationMakeExternalForm(http->auth_ref, &auth_extrn);
 
     if (status == errAuthorizationSuccess)
     {
@@ -583,5 +583,5 @@ cups_local_auth(http_t *http)               /* I - HTTP connection to server */
 
 
 /*
- * End of "$Id: auth.c 6397 2007-03-25 23:33:32Z mike $".
+ * End of "$Id: auth.c 6499 2007-04-30 21:44:43Z mike $".
  */
index 54103fffab70694ca736d307cd181e77748779fe..88b4d50de7d9a708569559c79c4dddad171cb498 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: cups.h 6187 2007-01-10 16:20:42Z mike $"
+ * "$Id: cups.h 6506 2007-05-03 18:12:35Z mike $"
  *
  *   API definitions for the Common UNIX Printing System (CUPS).
  *
@@ -244,6 +244,10 @@ extern int         cupsRemoveOption(const char *name, int num_options,
 extern cups_file_t     *cupsTempFile2(char *filename, int len);
 
 /**** New in CUPS 1.3 ****/
+extern ipp_t           *cupsDoIORequest(http_t *http, ipp_t *request,
+                                        const char *resource, int infile,
+                                        int outfile);
+extern char            *cupsGetServerPPD(http_t *http, const char *name);
 extern int             cupsRemoveDest(const char *name,
                                       const char *instance,
                                       int num_dests, cups_dest_t **dests);
@@ -260,5 +264,5 @@ extern void         cupsSetDefaultDest(const char *name,
 #endif /* !_CUPS_CUPS_H_ */
 
 /*
- * End of "$Id: cups.h 6187 2007-01-10 16:20:42Z mike $".
+ * End of "$Id: cups.h 6506 2007-05-03 18:12:35Z mike $".
  */
index a0f323b167a8fe7a47240782dd30f8c28974bf4f..4b09a427d7641c75df33513a4b81acdba210b513 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: globals.c 6253 2007-02-10 18:48:40Z mike $"
+ * "$Id: globals.c 6499 2007-04-30 21:44:43Z mike $"
  *
  *   Global variable access routines for the Common UNIX Printing System (CUPS).
  *
@@ -180,11 +180,6 @@ globals_destructor(void *value)            /* I - Data to free */
 
   cupsFreeOptions(cg->cupsd_num_settings, cg->cupsd_settings);
 
-#ifdef HAVE_AUTHORIZATION_H
-  if (cg->auth_ref)
-    AuthorizationFree(cg->auth_ref, kAuthorizationFlagDefaults);
-#endif /* HAVE_AUTHORIZATION_H */
-
   free(value);
 }
 
@@ -231,5 +226,5 @@ _cupsGlobals(void)
 
 
 /*
- * End of "$Id: globals.c 6253 2007-02-10 18:48:40Z mike $".
+ * End of "$Id: globals.c 6499 2007-04-30 21:44:43Z mike $".
  */
index 0db1dac2ffa02b916d31d5b29a4f0aa35ccd3996..09fdbcad9d116948326440c6f296667df1c6cc1d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: globals.h 6253 2007-02-10 18:48:40Z mike $"
+ * "$Id: globals.h 6499 2007-04-30 21:44:43Z mike $"
  *
  *   Global variable definitions for the Common UNIX Printing System (CUPS).
  *
 #    include <pthread.h>
 #  endif /* HAVE_PTHREAD_H */
 
-#  ifdef HAVE_AUTHORIZATION_H
-#    include <Security/Authorization.h>
-#  endif /* HAVE_AUTHORIZATION_H */
-
 
 /*
  * C++ magic...
@@ -130,11 +126,6 @@ typedef struct _cups_globals_s             /**** CUPS global state data ****/
                                        /* Default printer */
   char                 ppd_filename[HTTP_MAX_URI];
                                        /* PPD filename */
-
-#ifdef HAVE_AUTHORIZATION_H
-  /* auth.c */
-  AuthorizationRef     auth_ref;       /* Authorization ref */
-#endif /* HAVE_AUTHORIZATION_H */
 } _cups_globals_t;
 
 
@@ -157,5 +148,5 @@ extern void         _cupsSetError(ipp_status_t status, const char *message);
 #endif /* !_CUPS_GLOBALS_H_ */
 
 /*
- * End of "$Id: globals.h 6253 2007-02-10 18:48:40Z mike $".
+ * End of "$Id: globals.h 6499 2007-04-30 21:44:43Z mike $".
  */
index 60dede364c9b79dfffcdda344d05d4db18192e4c..fdf3d2da5f7c44170bec7b03ae225e91d866d782 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: http-private.h 6187 2007-01-10 16:20:42Z mike $"
+ * "$Id: http-private.h 6499 2007-04-30 21:44:43Z mike $"
  *
  *   Private HTTP definitions for the Common UNIX Printing System (CUPS).
  *
 #    endif /* !HAVE_GSS_C_NT_HOSTBASED_SERVICE */
 #  endif /* HAVE_GSSAPI */
 
+#  ifdef HAVE_AUTHORIZATION_H
+#    include <Security/Authorization.h>
+#  endif /* HAVE_AUTHORIZATION_H */
+
 #  if defined(__sgi) || (defined(__APPLE__) && !defined(_SOCKLEN_T))
 /*
  * IRIX and MacOS X 10.2.x do not define socklen_t, and in fact use an int instead of
@@ -193,6 +197,9 @@ struct _http_s                              /**** HTTP connection structure. ****/
   gss_ctx_id_t         gssctx;         /* Authentication context @since CUPS 1.3@ */
   gss_name_t           gssname;        /* Authentication server name @since CUPS 1.3@ */
 #  endif /* HAVE_GSSAPI */
+#  ifdef HAVE_AUTHORIZATION_H
+  AuthorizationRef     auth_ref;       /* Authorization ref */
+#  endif /* HAVE_AUTHORIZATION_H */
 };
 
 
@@ -265,5 +272,5 @@ extern void _cups_freeifaddrs(struct ifaddrs *addrs);
 #endif /* !_CUPS_HTTP_PRIVATE_H_ */
 
 /*
- * End of "$Id: http-private.h 6187 2007-01-10 16:20:42Z mike $".
+ * End of "$Id: http-private.h 6499 2007-04-30 21:44:43Z mike $".
  */
index 7a6f6840851f8baad1c4a9ad97ecd1cdfe02b21a..251321d5141a5ebeca2d7d34e6976afe122276d2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: http.c 6285 2007-02-16 01:10:55Z mike $"
+ * "$Id: http.c 6499 2007-04-30 21:44:43Z mike $"
  *
  *   HTTP routines for the Common UNIX Printing System (CUPS).
  *
@@ -335,6 +335,11 @@ httpClose(http_t *http)                    /* I - HTTP connection */
     major_status = gss_release_name(&minor_status, &http->gssname);
 #endif /* HAVE_GSSAPI */
 
+#ifdef HAVE_AUTHORIZATION_H
+  if (http->auth_ref)
+    AuthorizationFree(http->auth_ref, kAuthorizationFlagDefaults);
+#endif /* HAVE_AUTHORIZATION_H */
+
   httpClearFields(http);
 
   if (http->authstring && http->authstring != http->_authstring)
@@ -2574,10 +2579,12 @@ http_send(http_t       *http,   /* I - HTTP connection */
   httpClearFields(http);
 
  /*
-  * The Kerberos authentication string can only be used once...
+  * The Kerberos and AuthRef authentication strings can only be used once...
   */
 
-  if (http->authstring && !strncmp(http->authstring, "Negotiate", 9))
+  if (http->authstring && 
+      (!strncmp(http->authstring, "Negotiate", 9) || 
+       !strncmp(http->authstring, "AuthRef", 7)))
   {
     http->_authstring[0] = '\0';
 
@@ -3156,5 +3163,5 @@ http_write_ssl(http_t     *http,  /* I - HTTP connection */
 
 
 /*
- * End of "$Id: http.c 6285 2007-02-16 01:10:55Z mike $".
+ * End of "$Id: http.c 6499 2007-04-30 21:44:43Z mike $".
  */
index f868e399665e1f0da7f6cb403e6148d91656838d..3ff58417f0612fe20f74064144c4f2544a68ae9d 100644 (file)
@@ -1,10 +1,10 @@
 /*
- * "$Id: ipp-support.c 5903 2006-08-29 20:45:15Z mike $"
+ * "$Id: ipp-support.c 6503 2007-05-01 23:06:44Z mike $"
  *
  *   Internet Printing Protocol support functions for the Common UNIX
  *   Printing System (CUPS).
  *
- *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
  *   property of Easy Software Products and are protected by Federal
@@ -157,7 +157,8 @@ static char * const ipp_std_ops[] =
                  "CUPS-Get-Devices",
                  "CUPS-Get-PPDs",
                  "CUPS-Move-Job",
-                 "CUPS-Authenticate-Job"
+                 "CUPS-Authenticate-Job",
+                 "CUPS-Get-PPD"
                };
 
 
@@ -179,6 +180,8 @@ ippErrorString(ipp_status_t error)  /* I - Error status */
     return (ipp_status_oks[error]);
   else if (error == IPP_REDIRECTION_OTHER_SITE)
     return ("redirection-other-site");
+  else if (error == CUPS_SEE_OTHER)
+    return ("cups-see-other");
   else if (error >= IPP_BAD_REQUEST && error <= IPP_PRINT_SUPPORT_FILE_NOT_FOUND)
     return (ipp_status_400s[error - IPP_BAD_REQUEST]);
   else if (error >= IPP_INTERNAL_ERROR && error <= IPP_PRINTER_IS_DEACTIVATED)
@@ -213,6 +216,9 @@ ippErrorValue(const char *name)             /* I - Name */
   if (!strcasecmp(name, "redirection-other-site"))
     return (IPP_REDIRECTION_OTHER_SITE);
 
+  if (!strcasecmp(name, "cups-see-other"))
+    return (CUPS_SEE_OTHER);
+
   for (i = 0; i < (sizeof(ipp_status_400s) / sizeof(ipp_status_400s[0])); i ++)
     if (!strcasecmp(name, ipp_status_400s[i]))
       return ((ipp_status_t)(i + 0x400));
@@ -245,7 +251,7 @@ ippOpString(ipp_op_t op)            /* I - Operation ID */
     return (ipp_std_ops[op]);
   else if (op == IPP_PRIVATE)
     return ("windows-ext");
-  else if (op >= CUPS_GET_DEFAULT && op <= CUPS_AUTHENTICATE_JOB)
+  else if (op >= CUPS_GET_DEFAULT && op <= CUPS_GET_PPD)
     return (ipp_cups_ops[op - CUPS_GET_DEFAULT]);
 
  /*
@@ -364,5 +370,5 @@ ippSetPort(int p)                   /* I - Port number to use */
 
 
 /*
- * End of "$Id: ipp-support.c 5903 2006-08-29 20:45:15Z mike $".
+ * End of "$Id: ipp-support.c 6503 2007-05-01 23:06:44Z mike $".
  */
index d4ae704ea0a46c718d135f57f52cb8203cc79203..a374487765dbe4bdc7011b2451f1d25023ebb4a6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: ipp.h 5873 2006-08-24 14:37:24Z mike $"
+ * "$Id: ipp.h 6503 2007-05-01 23:06:44Z mike $"
  *
  *   Internet Printing Protocol definitions for the Common UNIX Printing
  *   System (CUPS).
@@ -254,7 +254,8 @@ typedef enum ipp_op_e                       /**** IPP operations... ****/
   CUPS_GET_DEVICES,                    /* Get a list of supported devices */
   CUPS_GET_PPDS,                       /* Get a list of supported drivers */
   CUPS_MOVE_JOB,                       /* Move a job to a different printer */
-  CUPS_AUTHENTICATE_JOB                        /* Authenticate a job @since CUPS 1.2@ */
+  CUPS_AUTHENTICATE_JOB,               /* Authenticate a job @since CUPS 1.2@ */
+  CUPS_GET_PPD                         /* Get a PPD file @since CUPS 1.3@ */
 } ipp_op_t;
 
 /* Old names for the operations */
@@ -271,7 +272,8 @@ typedef enum ipp_status_e           /**** IPP status codes... ****/
   IPP_OK_TOO_MANY_EVENTS,              /* successful-ok-too-many-events */
   IPP_OK_BUT_CANCEL_SUBSCRIPTION,      /* successful-ok-but-cancel-subscription */
   IPP_OK_EVENTS_COMPLETE,              /* successful-ok-events-complete */
-  IPP_REDIRECTION_OTHER_SITE = 0x300,  /*  */
+  IPP_REDIRECTION_OTHER_SITE = 0x200,  /*  */
+  CUPS_SEE_OTHER = 0x280,              /* cups-see-other */
   IPP_BAD_REQUEST = 0x0400,            /* client-error-bad-request */
   IPP_FORBIDDEN,                       /* client-error-forbidden */
   IPP_NOT_AUTHENTICATED,               /* client-error-not-authenticated */
@@ -499,5 +501,5 @@ extern ipp_state_t  ippWriteIO(void *dst, ipp_iocb_t cb, int blocking,
 #endif /* !_CUPS_IPP_H_ */
 
 /*
- * End of "$Id: ipp.h 5873 2006-08-24 14:37:24Z mike $".
+ * End of "$Id: ipp.h 6503 2007-05-01 23:06:44Z mike $".
  */
index 78e22e8eed8a453ec2133fb6155fe812e33dbf61..21c6ad782bd02d7e784c72f3f6b040d66e428cef 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: language.c 6407 2007-03-27 17:45:12Z mike $"
+ * "$Id: language.c 6489 2007-04-30 17:55:15Z mike $"
  *
  *   I18N/language support for the Common UNIX Printing System (CUPS).
  *
@@ -984,6 +984,21 @@ _cupsMessageLookup(cups_array_t *a,        /* I - Message array */
  */
 
 #  ifdef HAVE_CF_LOCALE_ID
+
+typedef struct
+{
+  const char * const name;             /* Language name */
+  const char * const locale;           /* Locale name */
+} _apple_name_locale_t;
+
+static const _apple_name_locale_t apple_name_locale[] =
+{
+  { "en"       , "en_US" },
+  { "no"       , "nb"    },
+  { "zh-Hans"  , "zh_CN" },
+  { "zh-Hant"  , "zh_TW" }
+};
+
 /*
  * 'appleLangDefault()' - Get the default locale string.
  */
@@ -991,6 +1006,7 @@ _cupsMessageLookup(cups_array_t *a,        /* I - Message array */
 static const char *                    /* O - Locale string */
 appleLangDefault(void)
 {
+  int                  i;              /* Looping var */
   CFPropertyListRef    localizationList;
                                        /* List of localization data */
   CFStringRef          languageName;   /* Current name */
@@ -1033,9 +1049,30 @@ appleLangDefault(void)
                                 kCFStringEncodingASCII);
              CFRelease(localeName);
 
-             if (!strcmp(cg->language, "en"))
-               strlcpy(cg->language, "en_US.UTF-8", sizeof(cg->language));
-             else if (strchr(cg->language, '.') == NULL)
+            /*
+             * Map new language identifiers to locales...
+             */
+
+             for (i = 0;
+                  i < sizeof(apple_name_locale) / sizeof(apple_name_locale[0]);
+                  i++)
+             {
+               if (!strcmp(cg->language, apple_name_locale[i].name))
+               {
+                 strlcpy(cg->language, apple_name_locale[i].locale, 
+                         sizeof(cg->language));
+                 break;
+               }
+             }
+
+            /*
+             * Convert language subtag into region subtag...
+             */
+
+             if (cg->language[2] == '-')
+               cg->language[2] = '_';
+
+             if (strchr(cg->language, '.') == NULL)
                strlcat(cg->language, ".UTF-8", sizeof(cg->language));
            }
           }
@@ -1326,5 +1363,5 @@ cups_unquote(char       *d,               /* O - Unquoted string */
 
 
 /*
- * End of "$Id: language.c 6407 2007-03-27 17:45:12Z mike $".
+ * End of "$Id: language.c 6489 2007-04-30 17:55:15Z mike $".
  */
index ee88a790f8192b5c6cecba86fb305cfbc0ad3777..bf3a5303b4a78edcbee64ae2ffad32731044feb8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: localize.c 6388 2007-03-24 14:21:31Z mike $"
+ * "$Id: localize.c 6457 2007-04-17 18:40:55Z mike $"
  *
  *   PPD custom option routines for the Common UNIX Printing System (CUPS).
  *
@@ -96,6 +96,32 @@ ppdLocalize(ppd_file_t *ppd)         /* I - PPD file */
   strlcpy(ll_CC, lang->language, sizeof(ll_CC));
   strlcpy(ll, lang->language, sizeof(ll));
 
+  if (strlen(ll_CC) == 2)
+  {
+   /*
+    * Map "ll" to primary/origin country locales to have the best
+    * chance of finding a match...
+    */
+
+    if (!strcmp(ll_CC, "cs"))
+      strcpy(ll_CC, "cs_CZ");
+    else if (!strcmp(ll_CC, "en"))
+      strcpy(ll_CC, "en_US");
+    else if (!strcmp(ll_CC, "ja"))
+      strcpy(ll_CC, "ja_JP");
+    else if (!strcmp(ll_CC, "sv"))
+      strcpy(ll_CC, "sv_SE");
+    else if (!strcmp(ll_CC, "zh"))
+      strcpy(ll_CC, "zh_CN");          /* Simplified Chinese */
+    else
+    {
+      ll_CC[2] = '_';
+      ll_CC[3] = toupper(ll_CC[0] & 255);
+      ll_CC[4] = toupper(ll_CC[1] & 255);
+      ll_CC[5] = '\0';
+    }
+  }
+
   DEBUG_printf(("    lang->language=\"%s\", ll=\"%s\", ll_CC=\"%s\"...\n",
                 lang->language, ll, ll_CC));
 
@@ -239,5 +265,5 @@ ppd_text(ppd_file_t *ppd,           /* I - PPD file */
 
 
 /*
- * End of "$Id: localize.c 6388 2007-03-24 14:21:31Z mike $".
+ * End of "$Id: localize.c 6457 2007-04-17 18:40:55Z mike $".
  */
index 20a94fd4a0282a589dd06eb57bfb95c8d959bb0c..6f68d6b00cd8456fa908f395ee37c5b8857dc33d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: mark.c 6187 2007-01-10 16:20:42Z mike $"
+ * "$Id: mark.c 6477 2007-04-25 19:55:45Z mike $"
  *
  *   Option marking routines for the Common UNIX Printing System (CUPS).
  *
@@ -59,14 +59,15 @@ static void ppd_defaults(ppd_file_t *ppd, ppd_group_t *g);
  * 'ppdConflicts()' - Check to see if there are any conflicts.
  */
 
-int                            /* O - Number of conflicts found */
-ppdConflicts(ppd_file_t *ppd)  /* I - PPD to check */
+int                                    /* O - Number of conflicts found */
+ppdConflicts(ppd_file_t *ppd)          /* I - PPD to check */
 {
-  int          i, j,           /* Looping variables */
-               conflicts;      /* Number of conflicts */
-  ppd_const_t  *c;             /* Current constraint */
-  ppd_option_t *o1, *o2;       /* Options */
-  ppd_choice_t *c1, *c2;       /* Choices */
+  int          i,                      /* Looping variable */
+               conflicts;              /* Number of conflicts */
+  ppd_const_t  *c;                     /* Current constraint */
+  ppd_option_t *o1, *o2;               /* Options */
+  ppd_choice_t *c1, *c2;               /* Choices */
+  ppd_choice_t key;                    /* Search key */
 
 
   if (!ppd)
@@ -86,38 +87,45 @@ ppdConflicts(ppd_file_t *ppd)       /* I - PPD to check */
   * that conflict...
   */
 
-  for (i = ppd->num_consts, c = ppd->consts; i > 0; i --, c ++)
+  for (i = ppd->num_consts, c = ppd->consts, o1 = o2 = NULL, c1 = c2 = NULL;
+       i > 0;
+       i --, c ++)
   {
    /*
     * Grab pointers to the first option...
     */
 
-    o1 = ppdFindOption(ppd, c->option1);
+    if (!o1 || strcmp(c->option1, o1->keyword))
+    {
+      o1 = ppdFindOption(ppd, c->option1);
+      c1 = NULL;
+    }
 
     if (!o1)
       continue;
-    else if (c->choice1[0])
+    else if (c->choice1[0] && (!c1 || strcmp(c->choice1, c1->choice)))
     {
      /*
       * This constraint maps to a specific choice.
       */
 
-      c1 = ppdFindChoice(o1, c->choice1);
+      key.option = o1;
+
+      if ((c1 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
+          !c1->marked)
+        c1 = NULL;
     }
-    else
+    else if (!c1)
     {
      /*
       * This constraint applies to any choice for this option.
       */
 
-      for (j = o1->num_choices, c1 = o1->choices; j > 0; j --, c1 ++)
-        if (c1->marked)
-         break;
+      key.option = o1;
 
-      if (!j ||
-          !strcasecmp(c1->choice, "None") ||
-          !strcasecmp(c1->choice, "Off") ||
-          !strcasecmp(c1->choice, "False"))
+      if ((c1 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
+          (!strcasecmp(c1->choice, "None") || !strcasecmp(c1->choice, "Off") ||
+           !strcasecmp(c1->choice, "False")))
         c1 = NULL;
     }
 
@@ -125,32 +133,37 @@ ppdConflicts(ppd_file_t *ppd)     /* I - PPD to check */
     * Grab pointers to the second option...
     */
 
-    o2 = ppdFindOption(ppd, c->option2);
+    if (!o2 || strcmp(c->option2, o2->keyword))
+    {
+      o2 = ppdFindOption(ppd, c->option2);
+      c2 = NULL;
+    }
 
     if (!o2)
       continue;
-    else if (c->choice2[0])
+    else if (c->choice2[0] && (!c2 || strcmp(c->choice2, c2->choice)))
     {
      /*
       * This constraint maps to a specific choice.
       */
 
-      c2 = ppdFindChoice(o2, c->choice2);
+      key.option = o2;
+
+      if ((c2 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
+          !c2->marked)
+        c2 = NULL;
     }
-    else
+    else if (!c2)
     {
      /*
       * This constraint applies to any choice for this option.
       */
 
-      for (j = o2->num_choices, c2 = o2->choices; j > 0; j --, c2 ++)
-        if (c2->marked)
-         break;
+      key.option = o2;
 
-      if (!j ||
-          !strcasecmp(c2->choice, "None") ||
-          !strcasecmp(c2->choice, "Off") ||
-          !strcasecmp(c2->choice, "False"))
+      if ((c2 = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL &&
+          (!strcasecmp(c2->choice, "None") || !strcasecmp(c2->choice, "Off") ||
+           !strcasecmp(c2->choice, "False")))
         c2 = NULL;
     }
 
@@ -185,8 +198,8 @@ ppd_choice_t *                              /* O - Choice pointer or NULL */
 ppdFindChoice(ppd_option_t *o,         /* I - Pointer to option */
               const char   *choice)    /* I - Name of choice */
 {
-  int          i;              /* Looping var */
-  ppd_choice_t *c;             /* Current choice */
+  int          i;                      /* Looping var */
+  ppd_choice_t *c;                     /* Current choice */
 
 
   if (o == NULL || choice == NULL)
@@ -208,19 +221,13 @@ ppd_choice_t *                            /* O - Pointer to choice or NULL */
 ppdFindMarkedChoice(ppd_file_t *ppd,   /* I - PPD file */
                     const char *option)        /* I - Keyword/option name */
 {
-  int          i;              /* Looping var */
-  ppd_option_t *o;             /* Pointer to option */
-  ppd_choice_t *c;             /* Pointer to choice */
+  ppd_choice_t key;                    /* Search key for choice */
 
 
-  if ((o = ppdFindOption(ppd, option)) == NULL)
+  if ((key.option = ppdFindOption(ppd, option)) == NULL)
     return (NULL);
 
-  for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
-    if (c->marked)
-      return (c);
-
-  return (NULL);
+  return ((ppd_choice_t *)cupsArrayFind(ppd->marked, &key));
 }
 
 
@@ -279,25 +286,25 @@ ppdFindOption(ppd_file_t *ppd,            /* I - PPD file data */
  * 'ppdIsMarked()' - Check to see if an option is marked...
  */
 
-int                            /* O - Non-zero if option is marked */
-ppdIsMarked(ppd_file_t *ppd,   /* I - PPD file data */
-            const char *option,        /* I - Option/Keyword name */
-            const char *choice)        /* I - Choice name */
+int                                    /* O - Non-zero if option is marked */
+ppdIsMarked(ppd_file_t *ppd,           /* I - PPD file data */
+            const char *option,                /* I - Option/Keyword name */
+            const char *choice)                /* I - Choice name */
 {
-  ppd_option_t *o;             /* Option pointer */
-  ppd_choice_t *c;             /* Choice pointer */
+  ppd_choice_t key,                    /* Search key */
+               *c;                     /* Choice pointer */
 
 
-  if (ppd == NULL)
+  if (!ppd)
     return (0);
 
-  if ((o = ppdFindOption(ppd, option)) == NULL)
+  if ((key.option = ppdFindOption(ppd, option)) == NULL)
     return (0);
 
-  if ((c = ppdFindChoice(o, choice)) == NULL)
+  if ((c = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) == NULL)
     return (0);
 
-  return (c->marked);
+  return (!strcmp(c->choice, choice));
 }
 
 
@@ -306,15 +313,29 @@ ppdIsMarked(ppd_file_t *ppd,      /* I - PPD file data */
  */
 
 void
-ppdMarkDefaults(ppd_file_t *ppd)/* I - PPD file record */
+ppdMarkDefaults(ppd_file_t *ppd)       /* I - PPD file record */
 {
-  int          i;              /* Looping variables */
-  ppd_group_t  *g;             /* Current group */
+  int          i;                      /* Looping variables */
+  ppd_group_t  *g;                     /* Current group */
+  ppd_choice_t *c;                     /* Current choice */
 
 
-  if (ppd == NULL)
+  if (!ppd)
     return;
 
+ /*
+  * Clean out the marked array...
+  */
+
+  for (c = (ppd_choice_t *)cupsArrayFirst(ppd->marked);
+       c;
+       c = (ppd_choice_t *)cupsArrayNext(ppd->marked))
+    cupsArrayRemove(ppd->marked, c);
+
+ /*
+  * Then repopulate it with the defaults...
+  */
+
   for (i = ppd->num_groups, g = ppd->groups; i > 0; i --, g ++)
     ppd_defaults(ppd, g);
 }
@@ -336,7 +357,9 @@ ppdMarkOption(ppd_file_t *ppd,              /* I - PPD file record */
 {
   int          i, j;                   /* Looping vars */
   ppd_option_t *o;                     /* Option pointer */
-  ppd_choice_t *c;                     /* Choice pointer */
+  ppd_choice_t *c,                     /* Choice pointer */
+               *oldc,                  /* Old choice pointer */
+               key;                    /* Search key for choice */
   struct lconv *loc;                   /* Locale data */
 
 
@@ -358,8 +381,14 @@ ppdMarkOption(ppd_file_t *ppd,             /* I - PPD file record */
   if (!strcasecmp(option, "AP_D_InputSlot"))
   {
     if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
-      for (i = 0; i < o->num_choices; i ++)
-       o->choices[i].marked = 0;
+    {
+      key.option = o;
+      if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
+      {
+        oldc->marked = 0;
+        cupsArrayRemove(ppd->marked, oldc);
+      }
+    }
   }
 
  /*
@@ -542,73 +571,98 @@ ppdMarkOption(ppd_file_t *ppd,            /* I - PPD file record */
   * Option found; mark it and then handle unmarking any other options.
   */
 
-  c->marked = 1;
-
   if (o->ui != PPD_UI_PICKMANY)
   {
    /*
     * Unmark all other choices...
     */
 
-    for (i = o->num_choices, c = o->choices; i > 0; i --, c ++)
-      if (strcasecmp(c->choice, choice))
+    if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, c)) != NULL)
+    {
+      oldc->marked = 0;
+      cupsArrayRemove(ppd->marked, oldc);
+    }
+
+    if (!strcasecmp(option, "PageSize") || !strcasecmp(option, "PageRegion"))
+    {
+     /*
+      * Mark current page size...
+      */
+
+      for (j = 0; j < ppd->num_sizes; j ++)
+       ppd->sizes[j].marked = !strcasecmp(ppd->sizes[j].name,
+                                          choice);
+
+     /*
+      * Unmark the current PageSize or PageRegion setting, as
+      * appropriate...
+      */
+
+      if (!strcasecmp(option, "PageSize"))
       {
-        c->marked = 0;
+       if ((o = ppdFindOption(ppd, "PageRegion")) != NULL)
+        {
+          key.option = o;
+          if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
+          {
+            oldc->marked = 0;
+            cupsArrayRemove(ppd->marked, oldc);
+          }
+        }
+      }
+      else
+      {
+       if ((o = ppdFindOption(ppd, "PageSize")) != NULL)
+        {
+          key.option = o;
+          if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
+          {
+            oldc->marked = 0;
+            cupsArrayRemove(ppd->marked, oldc);
+          }
+        }
+      }
+    }
+    else if (!strcasecmp(option, "InputSlot"))
+    {
+     /*
+      * Unmark ManualFeed True and possibly mark ManualFeed False
+      * option...
+      */
 
-       if (!strcasecmp(option, "PageSize") ||
-           !strcasecmp(option, "PageRegion"))
-       {
-        /*
-         * Mark current page size...
-         */
-
-         for (j = 0; j < ppd->num_sizes; j ++)
-           ppd->sizes[j].marked = !strcasecmp(ppd->sizes[j].name,
-                                              choice);
-
-        /*
-         * Unmark the current PageSize or PageRegion setting, as
-         * appropriate...
-         */
-
-         if (!strcasecmp(option, "PageSize"))
-         {
-           if ((o = ppdFindOption(ppd, "PageRegion")) != NULL)
-             for (j = 0; j < o->num_choices; j ++)
-               o->choices[j].marked = 0;
-         }
-         else
-         {
-           if ((o = ppdFindOption(ppd, "PageSize")) != NULL)
-             for (j = 0; j < o->num_choices; j ++)
-               o->choices[j].marked = 0;
-         }
-       }
-       else if (!strcasecmp(option, "InputSlot"))
-       {
-        /*
-         * Unmark ManualFeed True and possibly mark ManualFeed False
-         * option...
-         */
-
-         if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL)
-           for (j = 0; j < o->num_choices; j ++)
-              o->choices[j].marked = !strcasecmp(o->choices[j].choice, "False");
-       }
-       else if (!strcasecmp(option, "ManualFeed") &&
-                !strcasecmp(choice, "True"))
-       {
-        /*
-         * Unmark InputSlot option...
-         */
+      if ((o = ppdFindOption(ppd, "ManualFeed")) != NULL)
+      {
+        key.option = o;
+        if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
+        {
+          oldc->marked = 0;
+          cupsArrayRemove(ppd->marked, oldc);
+        }
+      }
+    }
+    else if (!strcasecmp(option, "ManualFeed") &&
+            !strcasecmp(choice, "True"))
+    {
+     /*
+      * Unmark InputSlot option...
+      */
 
-         if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
-           for (j = 0; j < o->num_choices; j ++)
-              o->choices[j].marked = 0;
-       }
+      if ((o = ppdFindOption(ppd, "InputSlot")) != NULL)
+      {
+        key.option = o;
+        if ((oldc = (ppd_choice_t *)cupsArrayFind(ppd->marked, &key)) != NULL)
+        {
+          oldc->marked = 0;
+          cupsArrayRemove(ppd->marked, oldc);
+        }
       }
+    }
   }
 
+  c->marked = 1;
+
+  cupsArrayAdd(ppd->marked, c);
+
  /*
   * Return the number of conflicts...
   */
@@ -666,9 +720,6 @@ ppd_defaults(ppd_file_t  *ppd,      /* I - PPD file */
   ppd_group_t  *sg;            /* Current sub-group */
 
 
-  if (g == NULL)
-    return;
-
   for (i = g->num_options, o = g->options; i > 0; i --, o ++)
     if (strcasecmp(o->keyword, "PageRegion") != 0)
       ppdMarkOption(ppd, o->keyword, o->defchoice);
@@ -679,5 +730,5 @@ ppd_defaults(ppd_file_t  *ppd,      /* I - PPD file */
 
 
 /*
- * End of "$Id: mark.c 6187 2007-01-10 16:20:42Z mike $".
+ * End of "$Id: mark.c 6477 2007-04-25 19:55:45Z mike $".
  */
index c25e57ce24729c9a8a8e3cb15e20b8e0bf3e71c2..d68a1209cd1cb664d21b97f85c3c272c3b9a986d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: ppd.c 6445 2007-04-04 23:43:26Z mike $"
+ * "$Id: ppd.c 6479 2007-04-27 11:44:10Z mike $"
  *
  *   PPD file routines for the Common UNIX Printing System (CUPS).
  *
@@ -48,6 +48,8 @@
  *   ppd_add_choice()       - Add a choice to an option.
  *   ppd_add_size()         - Add a page size.
  *   ppd_compare_attrs()    - Compare two attributes.
+ *   ppd_compare_choices()  - Compare two choices...
+ *   ppd_compare_consts()   - Compare two constraints.
  *   ppd_compare_coptions() - Compare two custom options.
  *   ppd_compare_cparams()  - Compare two custom parameters.
  *   ppd_compare_options()  - Compare two options.
@@ -58,6 +60,7 @@
  *   ppd_get_cparam()       - Get a custom parameter record.
  *   ppd_get_group()        - Find or create the named group as needed.
  *   ppd_get_option()       - Find or create the named option as needed.
+ *   ppd_hash_option()      - Generate a hash of the option name...
  *   ppd_read()             - Read a line from a PPD file, skipping comment
  *                            lines as necessary.
  */
@@ -90,6 +93,8 @@
 #define PPD_TEXT       4               /* Line contained human-readable text */
 #define PPD_STRING     8               /* Line contained a string or code */
 
+#define PPD_HASHSIZE   512             /* Size of hash */
+
 
 /*
  * Local functions...
@@ -101,6 +106,8 @@ static ppd_attr_t   *ppd_add_attr(ppd_file_t *ppd, const char *name,
 static ppd_choice_t    *ppd_add_choice(ppd_option_t *option, const char *name);
 static ppd_size_t      *ppd_add_size(ppd_file_t *ppd, const char *name);
 static int             ppd_compare_attrs(ppd_attr_t *a, ppd_attr_t *b);
+static int             ppd_compare_choices(ppd_choice_t *a, ppd_choice_t *b);
+static int             ppd_compare_consts(ppd_const_t *a, ppd_const_t *b);
 static int             ppd_compare_coptions(ppd_coption_t *a,
                                             ppd_coption_t *b);
 static int             ppd_compare_cparams(ppd_cparam_t *a, ppd_cparam_t *b);
@@ -116,6 +123,7 @@ static ppd_group_t  *ppd_get_group(ppd_file_t *ppd, const char *name,
                                       const char *text, _cups_globals_t *cg,
                                       cups_encoding_t encoding);
 static ppd_option_t    *ppd_get_option(ppd_group_t *group, const char *name);
+static int             ppd_hash_option(ppd_option_t *option);
 static int             ppd_read(cups_file_t *fp, char *keyword, char *option,
                                 char *text, char **string, int ignoreblank,
                                 _cups_globals_t *cg);
@@ -184,6 +192,7 @@ ppdClose(ppd_file_t *ppd)           /* I - PPD file record */
   }
 
   cupsArrayDelete(ppd->options);
+  cupsArrayDelete(ppd->marked);
 
  /*
   * Free any page sizes...
@@ -1892,7 +1901,9 @@ ppdOpen2(cups_file_t *fp)         /* I - File to read from */
   * each choice and custom option...
   */
 
-  ppd->options = cupsArrayNew((cups_array_func_t)ppd_compare_options, NULL);
+  ppd->options = cupsArrayNew2((cups_array_func_t)ppd_compare_options, NULL,
+                               (cups_ahash_func_t)ppd_hash_option,
+                              PPD_HASHSIZE);
 
   for (i = ppd->num_groups, group = ppd->groups;
        i > 0;
@@ -1915,6 +1926,20 @@ ppdOpen2(cups_file_t *fp)                /* I - File to read from */
     }
   }
 
+ /*
+  * Sort the constraints...
+  */
+
+  if (ppd->num_consts > 1)
+    qsort(ppd->consts, ppd->num_consts, sizeof(ppd_const_t),
+          (int (*)(const void *, const void *))ppd_compare_consts);
+
+ /*
+  * Create an array to track the marked choices...
+  */
+
+  ppd->marked = cupsArrayNew((cups_array_func_t)ppd_compare_choices, NULL);
+
  /*
   * Return the PPD file structure...
   */
@@ -2208,6 +2233,40 @@ ppd_compare_attrs(ppd_attr_t *a, /* I - First attribute */
 }
 
 
+/*
+ * 'ppd_compare_choices()' - Compare two choices...
+ */
+
+static int                             /* O - Result of comparison */
+ppd_compare_choices(ppd_choice_t *a,   /* I - First choice */
+                    ppd_choice_t *b)   /* I - Second choice */
+{
+  return (a->option - b->option);
+}
+
+
+/*
+ * 'ppd_compare_consts()' - Compare two constraints.
+ */
+
+static int                             /* O - Result of comparison */
+ppd_compare_consts(ppd_const_t *a,     /* I - First constraint */
+                   ppd_const_t *b)     /* I - Second constraint */
+{
+  int  ret;                            /* Result of comparison */
+
+
+  if ((ret = strcmp(a->option1, b->option1)) != 0)
+    return (ret);
+  else if ((ret = strcmp(a->choice1, b->choice1)) != 0)
+    return (ret);
+  else if ((ret = strcmp(a->option2, b->option2)) != 0)
+    return (ret);
+  else
+    return (strcmp(a->choice2, b->choice2));
+}
+
+
 /*
  * 'ppd_compare_coptions()' - Compare two custom options.
  */
@@ -2545,6 +2604,24 @@ ppd_get_option(ppd_group_t *group,       /* I - Group */
 }
 
 
+/*
+ * 'ppd_hash_option()' - Generate a hash of the option name...
+ */
+
+static int                             /* O - Hash index */
+ppd_hash_option(ppd_option_t *option)  /* I - Option */
+{
+  int          hash = 0;               /* Hash index */
+  const char   *k;                     /* Pointer into keyword */
+
+
+  for (hash = option->keyword[0], k = option->keyword + 1; *k;)
+    hash = 33 * hash + *k++;
+
+  return (hash & 511);
+}
+
+
 /*
  * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as
  *                necessary.
@@ -3102,5 +3179,5 @@ ppd_read(cups_file_t    *fp,              /* I - File to read from */
 
 
 /*
- * End of "$Id: ppd.c 6445 2007-04-04 23:43:26Z mike $".
+ * End of "$Id: ppd.c 6479 2007-04-27 11:44:10Z mike $".
  */
index d7688c3d5239f6deb93f739a8086257780a03701..b0ded47ccba1dfc266037ed2b3f5f16ac9365e9a 100644 (file)
@@ -1,10 +1,10 @@
 /*
- * "$Id: ppd.h 5238 2006-03-07 04:41:42Z mike $"
+ * "$Id: ppd.h 6477 2007-04-25 19:55:45Z mike $"
  *
  *   PostScript Printer Description definitions for the Common UNIX Printing
  *   System (CUPS).
  *
- *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
  *   property of Easy Software Products and are protected by Federal
@@ -331,6 +331,9 @@ typedef struct ppd_file_s           /**** PPD File ****/
   cups_array_t *sorted_attrs;          /* Attribute lookup array @since CUPS 1.2@ @private@ */
   cups_array_t *options;               /* Option lookup array @since CUPS 1.2@ @private@ */
   cups_array_t *coptions;              /* Custom options array @since CUPS 1.2@ @private@ */
+
+  /**** New in CUPS 1.3 ****/
+  cups_array_t *marked;                /* Marked choices @since CUPS 1.3@ @private@ */
 } ppd_file_t;
 
 
@@ -405,5 +408,5 @@ extern ppd_file_t   *ppdOpen2(cups_file_t *fp);
 #endif /* !_CUPS_PPD_H_ */
 
 /*
- * End of "$Id: ppd.h 5238 2006-03-07 04:41:42Z mike $".
+ * End of "$Id: ppd.h 6477 2007-04-25 19:55:45Z mike $".
  */
index 95870a8fc7d024a3490408d223443e49e6244216..5e80fd645f60b7b1e081cc76883181fdfa1a91e7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: request.c 6416 2007-03-30 18:30:33Z mike $"
+ * "$Id: request.c 6506 2007-05-03 18:12:35Z mike $"
  *
  *   IPP utilities for the Common UNIX Printing System (CUPS).
  *
@@ -45,6 +45,9 @@
 #else
 #  include <unistd.h>
 #endif /* WIN32 || __EMX__ */
+#ifndef O_BINARY
+#  define O_BINARY 0
+#endif /* O_BINARY */
 
 
 /*
@@ -60,20 +63,71 @@ cupsDoFileRequest(http_t     *http, /* I - HTTP connection to server */
                   ipp_t      *request, /* I - IPP request */
                   const char *resource,        /* I - HTTP resource for POST */
                  const char *filename) /* I - File to send or NULL for none */
+{
+  ipp_t                *response;              /* IPP response data */
+  int          infile;                 /* Input file */
+
+
+  if (filename)
+  {
+    if ((infile = open(filename, O_RDONLY | O_BINARY)) < 0)
+    {
+     /*
+      * Can't get file information!
+      */
+
+      _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
+                    strerror(errno));
+
+      ippDelete(request);
+
+      return (NULL);
+    }
+  }
+  else
+    infile = -1;
+
+  response = cupsDoIORequest(http, request, resource, infile, -1);
+
+  if (infile >= 0)
+    close(infile);
+
+  return (response);
+}
+
+
+/*
+ * 'cupsDoIORequest()' - Do an IPP request with file descriptors.
+ *
+ * This function sends the IPP request to the specified server, retrying
+ * and authenticating as necessary.  The request is freed with ippDelete()
+ * after receiving a valid IPP response.
+ *
+ * If "infile" is a valid file descriptor, cupsDoIORequest() copies
+ * all of the data from the file after the IPP request message.
+ *
+ * If "outfile" is a valid file descriptor, cupsDoIORequest() copies
+ * all of the data after the IPP response message to the file.
+ *
+ * @since CUPS 1.3@
+ */
+
+ipp_t *                                        /* O - Response data */
+cupsDoIORequest(http_t     *http,      /* I - HTTP connection to server */
+                ipp_t      *request,   /* I - IPP request */
+                const char *resource,  /* I - HTTP resource for POST */
+               int        infile,      /* I - File to read from or -1 for none */
+               int        outfile)     /* I - File to write to or -1 for none */
 {
   ipp_t                *response;              /* IPP response data */
   size_t       length;                 /* Content-Length value */
   http_status_t        status;                 /* Status of HTTP request */
   int          got_status;             /* Did we get the status? */
   ipp_state_t  state;                  /* State of IPP processing */
-  FILE         *file;                  /* File to send */
   struct stat  fileinfo;               /* File information */
   int          bytes;                  /* Number of bytes read/written */
   char         buffer[32768];          /* Output buffer */
   http_status_t        expect;                 /* Expect: header to use */
-#ifdef HAVE_AUTHORIZATION_H
-  _cups_globals_t *cg = _cupsGlobals();        /* Global data */
-#endif /* HAVE_AUTHORIZATION_H */
 
 
   DEBUG_printf(("cupsDoFileRequest(%p, %p, \'%s\', \'%s\')\n",
@@ -94,16 +148,16 @@ cupsDoFileRequest(http_t     *http,        /* I - HTTP connection to server */
   * See if we have a file to send...
   */
 
-  if (filename != NULL)
+  if (infile >= 0)
   {
-    if (stat(filename, &fileinfo))
+    if (fstat(infile, &fileinfo))
     {
      /*
       * Can't get file information!
       */
 
       _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
-                     strerror(errno));
+                    strerror(errno));
 
       ippDelete(request);
 
@@ -126,23 +180,7 @@ cupsDoFileRequest(http_t     *http,        /* I - HTTP connection to server */
 
       return (NULL);
     }
-
-    if ((file = fopen(filename, "rb")) == NULL)
-    {
-     /*
-      * Can't open file!
-      */
-
-      _cupsSetError(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED,
-                     strerror(errno));
-
-      ippDelete(request);
-
-      return (NULL);
-    }
   }
-  else
-    file = NULL;
 
 #ifdef HAVE_SSL
  /*
@@ -174,8 +212,15 @@ cupsDoFileRequest(http_t     *http,        /* I - HTTP connection to server */
     */
 
     length = ippLength(request);
-    if (filename)
+    if (infile >= 0)
+    {
+#ifndef WIN32
+      if (!S_ISREG(fileinfo.st_mode))
+        length = 0;                    /* Chunk when piping */
+      else
+#endif /* !WIN32 */
       length += fileinfo.st_size;
+    }
 
     httpClearFields(http);
     httpSetLength(http, length);
@@ -235,7 +280,7 @@ cupsDoFileRequest(http_t     *http, /* I - HTTP connection to server */
     else if (httpCheck(http))
       status = httpUpdate(http);
 
-    if (status == HTTP_CONTINUE && state == IPP_DATA && filename)
+    if (status == HTTP_CONTINUE && state == IPP_DATA && infile >= 0)
     {
       DEBUG_puts("cupsDoFileRequest: file write...");
 
@@ -243,9 +288,12 @@ cupsDoFileRequest(http_t     *http,        /* I - HTTP connection to server */
       * Send the file...
       */
 
-      rewind(file);
+#ifndef WIN32
+      if (S_ISREG(fileinfo.st_mode))
+#endif /* WIN32 */
+      lseek(infile, 0, SEEK_SET);
 
-      while ((bytes = (int)fread(buffer, 1, sizeof(buffer), file)) > 0)
+      while ((bytes = (int)read(infile, buffer, sizeof(buffer))) > 0)
       {
        if (httpCheck(http))
        {
@@ -377,21 +425,26 @@ cupsDoFileRequest(http_t     *http,       /* I - HTTP connection to server */
 
        break;
       }
-    }
-  }
-
- /*
-  * Close the file if needed...
-  */
-
-  if (filename != NULL)
-    fclose(file);
+      else if (outfile >= 0)
+      {
+       /*
+        * Write trailing data to file...
+       */
 
- /*
-  * Flush any remaining data...
-  */
+       while ((bytes = (int)httpRead2(http, buffer, sizeof(buffer))) > 0)
+         if (write(outfile, buffer, bytes) < bytes)
+           break;
+      }
+      else
+      {
+       /*
+        * Flush any remaining data...
+        */
 
-  httpFlush(http);
+        httpFlush(http);
+      }
+    }
+  }
 
  /*
   * Delete the original request and return the response...
@@ -450,18 +503,6 @@ cupsDoFileRequest(http_t     *http,        /* I - HTTP connection to server */
     }
   }
 
-#ifdef HAVE_AUTHORIZATION_H
- /*
-  * Delete any authorization reference created for this request...
-  */
-  
-  if (cg->auth_ref)
-  {
-    AuthorizationFree(cg->auth_ref, kAuthorizationFlagDefaults);
-    cg->auth_ref = NULL;
-  }
-#endif /* HAVE_AUTHORIZATION_H */
-
   return (response);
 }
 
@@ -510,5 +551,5 @@ _cupsSetError(ipp_status_t status,  /* I - IPP status code */
 
 
 /*
- * End of "$Id: request.c 6416 2007-03-30 18:30:33Z mike $".
+ * End of "$Id: request.c 6506 2007-05-03 18:12:35Z mike $".
  */
index 0e321ce0c00e0b842183615d81ea9187df0dee55..9da9f15331723828e244979c344d619b4a30c2a8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: util.c 6138 2006-12-06 18:52:39Z mike $"
+ * "$Id: util.c 6506 2007-05-03 18:12:35Z mike $"
  *
  *   Printing utilities for the Common UNIX Printing System (CUPS).
  *
@@ -40,6 +40,7 @@
  *   cupsGetPPD2()          - Get the PPD file for a printer on the specified
  *                            server.
  *   cupsGetPrinters()      - Get a list of printers from the default server.
+ *   cupsGetServerPPD()     - Get an available PPD file from the server.
  *   cupsLastError()        - Return the last IPP status code.
  *   cupsLastErrorString()  - Return the last IPP status-message.
  *   cupsPrintFile()        - Print a file to a printer or class on the default
@@ -1069,6 +1070,82 @@ cupsGetPrinters(char ***printers)        /* O - Printers */
 }
 
 
+/*
+ * 'cupsGetServerPPD()' - Get an available PPD file from the server.
+ *
+ * This function returns the named PPD file from the server.  The
+ * list of available PPDs is provided by the IPP CUPS_GET_PPDS
+ * operation.
+ *
+ * You must remove (unlink) the PPD file when you are finished with
+ * it. The PPD filename is stored in a static location that will be
+ * overwritten on the next call to cupsGetPPD(), cupsGetPPD2(), or
+ * cupsGetServerPPD().
+ *
+ * @since CUPS 1.3@
+ */
+
+char *                                 /* O - Name of PPD file or NULL on error */
+cupsGetServerPPD(http_t     *http,     /* I - HTTP connection */
+                 const char *name)     /* I - Name of PPD file ("ppd-name") */
+{
+  int                  fd;             /* PPD file descriptor */
+  ipp_t                        *request;       /* IPP request */
+  _cups_globals_t      *cg = _cupsGlobals();
+                                       /* Pointer to library globals */
+
+
+ /*
+  * Range check input...
+  */
+
+  if (!http || !name)
+  {
+    if (!http)
+      _cupsSetError(IPP_INTERNAL_ERROR, "No HTTP connection!");
+    else
+      _cupsSetError(IPP_INTERNAL_ERROR, "No PPD name!");
+
+    return (NULL);
+  }
+
+ /*
+  * Get a temp file...
+  */
+
+  if ((fd = cupsTempFd(cg->ppd_filename, sizeof(cg->ppd_filename))) < 0)
+  {
+   /*
+    * Can't open file; close the server connection and return NULL...
+    */
+
+    _cupsSetError(IPP_INTERNAL_ERROR, strerror(errno));
+
+    return (NULL);
+  }
+
+ /*
+  * Get the PPD file...
+  */
+
+  request = ippNewRequest(CUPS_GET_PPD);
+  ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "ppd-name", NULL,
+               name);
+
+  ippDelete(cupsDoIORequest(http, request, "/", -1, fd));
+
+  close(fd);
+
+  if (cupsLastError() != IPP_OK)
+  {
+    unlink(cg->ppd_filename);
+    return (NULL);
+  }
+  else
+    return (cg->ppd_filename);
+}
+
+
 /*
  * 'cupsLastError()' - Return the last IPP status code.
  */
@@ -1660,5 +1737,5 @@ cups_get_printer_uri(
 
 
 /*
- * End of "$Id: util.c 6138 2006-12-06 18:52:39Z mike $".
+ * End of "$Id: util.c 6506 2007-05-03 18:12:35Z mike $".
  */
index 20a17d3a87ba378efb6af8ed051e17b8e5f932bd..d42b384dd42431795ff65bc39e65d7403cae8801 100644 (file)
@@ -1,7 +1,7 @@
 <HTML>
 <!-- SECTION: Getting Started -->
 <HEAD>
-       <TITLE>Printing and Options</TITLE>
+       <TITLE>Command-Line Printing and Options</TITLE>
 </HEAD>
 <BODY>
 
@@ -171,6 +171,33 @@ lpstat
 </PRE>
 
 
+<H2 CLASS="title"><A NAME="LPMOVE">Moving a Print Job</A></H2>
+
+<P>The <A HREF="man-lpmove.html">lpmove(8)</A> command moves a print
+job to a new printer or class:</P>
+
+<PRE CLASS="command">
+lpmove <I>job-id</I> <i>destination</i>
+</PRE>
+
+<P>The <I>job-id</I> is the number that was reported to you by
+the <B>lp</B> or <B>lpstat</B> commands. <i>Destination</i> is the
+name of a printer or class that you want to actually print the job.
+
+<BLOCKQUOTE><B>Note:</B>
+
+<P>The <B>lpmove</B> command is located in the system command
+directory (typically <VAR>/usr/sbin</VAR> or <VAR>/usr/local/sbin</VAR>),
+and so may not be in your command path. Specify the full path to the
+command if you get a "command not found" error, for example:
+
+<PRE CLASS="command">
+/usr/sbin/lpmove foo-123 bar
+</PRE>
+
+</BLOCKQUOTE>
+
+
 <H2 CLASS="title"><A NAME="OPTIONS">Standard Printing Options</A></H2>
 
 <P>The following options apply when printing all types of
similarity index 98%
rename from doc/help/ref-cupsd-conf.html
rename to doc/help/ref-cupsd-conf.html.in
index 997b479a3350553eebeb8d497c1fbf749caf1709..e15c6c1d4f0c42cdaadf9c10a593729f89598a00 100644 (file)
@@ -67,7 +67,7 @@ server activity.</P>
 information to the system log instead of a plain file.</P>
 
 <P>The default access log file is
-<VAR>/var/log/cups/access_log</VAR>.</P>
+<VAR>@CUPS_LOGDIR@/access_log</VAR>.</P>
 
 
 <H2 CLASS="title"><A NAME="Allow">Allow</A></H2>
@@ -521,8 +521,7 @@ BrowseLocalProtocols cups dns-sd
 <P>The <CODE>BrowseLocalProtocols</CODE> directive specifies the
 protocols to use when advertising local shared printers on the
 network. Multiple protocols can be specified by separating them
-with spaces. The default is <CODE>cups</CODE>, which is a
-broadcast-based protocol.</P>
+with spaces. The default is <CODE>@CUPS_BROWSE_REMOTE_PROTOCOLS@</CODE>.</P>
 
 
 <H2 CLASS="title"><A NAME="BrowseOrder">BrowseOrder</A></H2>
@@ -616,7 +615,10 @@ BrowseProtocols cups dns-sd
 protocols to use when showing and advertising shared printers on
 the local network. Multiple protocols can be specified by
 separating them with spaces. The default protocol is
-<CODE>cups</CODE>, which is a broadcast-based protocol.</P>
+<CODE>@CUPS_BROWSE_LOCAL_PROTOCOLS@</CODE> for
+<A HREF="#BrowseLocalProtocols"><CODE>BrowseLocalProtocols</CODE></A> and
+<CODE>@CUPS_BROWSE_REMOTE_PROTOCOLS@</CODE> for
+<A HREF="#BrowseRemoteProtocols"><CODE>BrowseRemoteProtocols</CODE></A>.</P>
 
 <BLOCKQUOTE><B>Note:</B>
 
@@ -698,8 +700,7 @@ BrowseRemoteProtocols cups dns-sd
 <P>The <CODE>BrowseRemoteProtocols</CODE> directive specifies the
 protocols to use when finding remote shared printers on the
 network. Multiple protocols can be specified by separating them
-with spaces. The default is <CODE>cups</CODE>, which is a
-broadcast-based protocol.</P>
+with spaces. The default is <CODE>@CUPS_BROWSE_REMOTE_PROTOCOLS@</CODE>.</P>
 
 
 <H2 CLASS="title"><A NAME="BrowseShortNames">BrowseShortNames</A></H2>
@@ -720,7 +721,7 @@ Short names are just the remote printer name, without the server
 same name, the printers will have long names ("printer@server1",
 "printer@server2".)</P>
 
-<P>The default value for this option is <CODE>Yes</CODE>.</P>
+<P>The default value for this option is <CODE>@CUPS_BROWSE_SHORT_NAMES@</CODE>.</P>
 
 
 <H2 CLASS="title"><A NAME="BrowseTimeout">BrowseTimeout</A></H2>
@@ -759,7 +760,7 @@ Browsing Off
 
 <P>The <CODE>Browsing</CODE> directive controls whether or not
 network printer browsing is enabled. The default setting is
-<CODE>On</CODE>.</P>
+<CODE>@CUPS_BROWSING@</CODE>.</P>
 
 <P>This directive does not enable sharing of local printers by
 itself; you must also use the <A
@@ -835,7 +836,7 @@ ConfigFilePerm 0640
 
 <P>The <CODE>ConfigFilePerm</CODE> directive specifies the
 permissions to use when writing configuration files. The default
-is 0640.</P>
+is @CUPS_CONFIG_FILE_PERM@.</P>
 
 
 <H2 CLASS="title"><A NAME="DataDir">DataDir</A></H2>
@@ -956,7 +957,7 @@ DefaultShared no
 
 <P>The <CODE>DefaultShared</CODE> directive specifies whether
 printers are shared (published) by default. The default is
-<CODE>yes</CODE>.</P>
+<CODE>@CUPS_DEFAULT_SHARED@</CODE>.</P>
 
 
 <H2 CLASS="title"><A NAME="Deny">Deny</A></H2>
@@ -1020,13 +1021,13 @@ DocumentRoot /foo/bar/doc/cups
 of web content for the HTTP server in CUPS. If an absolute path
 is not specified then it is assumed to be relative to the <A
 HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directory. The
-default directory is <VAR>/usr/share/doc/cups</VAR>.</P>
+default directory is <VAR>@CUPS_DOCROOT@</VAR>.</P>
 
 <P>Documents are first looked up in a sub-directory for the
 primary language requested by the client (e.g.
-<VAR>/usr/share/doc/cups/fr/...</VAR>) and then directly under
+<VAR>@CUPS_DOCROOT@/fr/...</VAR>) and then directly under
 the <CODE>DocumentRoot</CODE> directory (e.g.
-<VAR>/usr/share/doc/cups/...</VAR>), so it is possible to
+<VAR>@CUPS_DOCROOT@/...</VAR>), so it is possible to
 localize the web content by providing subdirectories for each
 language needed.</P>
 
@@ -1069,7 +1070,7 @@ ErrorLog syslog
 log file. If the filename is not absolute then it is assumed to
 be relative to the <A
 HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directory. The
-default error log file is <VAR>/var/log/cups/error_log</VAR>.</P>
+default error log file is <VAR>@CUPS_LOGDIR@/error_log</VAR>.</P>
 
 <P>The server name can be included in the filename by using
 <CODE>%s</CODE> in the name.</P>
@@ -1283,25 +1284,6 @@ performance problems with hostname lookups. Set this option to
 required.</P>
 
 
-<H2 CLASS="title"><A NAME="ImplicitClasses">ImplicitClasses</A></H2>
-
-<H3>Examples</H3>
-
-<PRE CLASS="command">
-ImplicitClasses On
-ImplicitClasses Off
-</PRE>
-
-<H3>Description</H3>
-
-<P>The <CODE>ImplicitClasses</CODE> directive controls whether
-implicit classes are created based upon the available network
-printers and classes. The default setting is <CODE>On</CODE> but
-is automatically turned <CODE>Off</CODE> if <A
-HREF="#Browsing"><CODE>Browsing</CODE></A> is turned
-<CODE>Off</CODE>.</P>
-
-
 <H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.10</SPAN><A NAME="ImplicitAnyClasses">ImplicitAnyClasses</A></H2>
 
 <H3>Examples</H3>
@@ -1322,6 +1304,25 @@ setting is <CODE>Off</CODE>.</P>
 must be enabled for this directive to have any effect.</P>
 
 
+<H2 CLASS="title"><A NAME="ImplicitClasses">ImplicitClasses</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+ImplicitClasses On
+ImplicitClasses Off
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>ImplicitClasses</CODE> directive controls whether
+implicit classes are created based upon the available network
+printers and classes. The default setting is
+<CODE>@CUPS_IMPLICIT_CLASSES@</CODE> but is automatically turned
+<CODE>Off</CODE> if <A HREF="#Browsing"><CODE>Browsing</CODE></A> is turned
+<CODE>Off</CODE>.</P>
+
+
 <H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.9</SPAN><A NAME="Include">Include</A></H2>
 
 <H3>Examples</H3>
@@ -1819,7 +1820,7 @@ LogFilePerm 0600
 
 <P>The <CODE>LogFilePerm</CODE> directive specifies the
 permissions to use when writing configuration files. The default
-is 0644.</P>
+is @CUPS_LOG_FILE_PERM@.</P>
 
 
 <H2 CLASS="title"><A NAME="LogLevel">LogLevel</A></H2>
@@ -1934,7 +1935,7 @@ MaxCopies 65535
 
 <P>The <CODE>MaxCopies</CODE> directive controls the maximum
 number of copies that a user can print of a job. The default is
-100 copies.</P>
+@CUPS_MAX_COPIES@ copies.</P>
 
 <BLOCKQUOTE><B>Note:</B>
 
@@ -2107,7 +2108,7 @@ PageLog syslog
 log file. If the filename is not absolute then it is assumed to
 be relative to the <A
 HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directory. The
-default page log file is <VAR>/var/log/cups/page_log</VAR>.</P>
+default page log file is <VAR>@CUPS_LOGDIR@/page_log</VAR>.</P>
 
 <P>The server name can be included in the filename by using
 <CODE>%s</CODE> in the name.</P>
@@ -2349,7 +2350,7 @@ RequestRoot /foo/bar/spool/cups
 incoming IPP requests and HTML forms. If an absolute path is not
 provided then it is assumed to be relative to the <A
 HREF="#ServerRoot"><CODE>ServerRoot</CODE></A> directory. The
-default request directory is <VAR>/var/spool/cups</VAR>.</P>
+default request directory is <VAR>@CUPS_REQUESTS@</VAR>.</P>
 
 
 <H2 CLASS="title"><SPAN CLASS="info">CUPS 1.1.7</SPAN><A NAME="Require">Require</A></H2>
@@ -2700,10 +2701,7 @@ SystemGroup root lpadmin
 <P>The <CODE>SystemGroup</CODE> directive specifies the system
 administration group for <CODE>System</CODE> authentication.
 Multiple groups can be listed, separated with spaces. The default
-is system-dependent and generally consists of all of the
-following groups, if present: <CODE>lpadmin</CODE>,
-<CODE>root</CODE>, <CODE>sys</CODE>, and/or
-<CODE>system</CODE>.</P>
+group list is <CODE>@CUPS_SYSTEM_GROUPS@</CODE>.</P>
 
 
 <H2 CLASS="title"><A NAME="TempDir">TempDir</A></H2>
@@ -2719,7 +2717,7 @@ TempDir /foo/bar/tmp
 
 <P>The <CODE>TempDir</CODE> directive specifies an absolute path
 for the directory to use for temporary files. The default
-directory is <VAR>/var/spool/cups/tmp</VAR>.</P>
+directory is <VAR>@CUPS_REQUESTS@/tmp</VAR>.</P>
 
 <P>Temporary directories must be world-writable and should have
 the "sticky" permission bit enabled so that other users cannot
@@ -2768,7 +2766,7 @@ advertising a default printer, the client's default printer is
 set to the first discovered printer, or to the implicit class for
 the same printer available from multiple servers.</P>
 
-<P>The default is <CODE>yes</CODE>.</P>
+<P>The default is <CODE>@CUPS_USE_NETWORK_DEFAULT@</CODE>.</P>
 
 
 <H2 CLASS="title"><A NAME="User">User</A></H2>
@@ -2784,7 +2782,7 @@ User guest
 
 <P>The <CODE>User</CODE> directive specifies the UNIX user that
 filter and CGI programs run as. The default user is
-<CODE>lp</CODE>.</P>
+<CODE>@CUPS_USER@</CODE>.</P>
 
 <BLOCKQUOTE><B>Note:</B>
 
index e3047f24bc1675073bf4af7cf5abd20353ac5670..71e18d6d6685a3ab1857d4665e3d7dc2e369ec87 100644 (file)
@@ -80,6 +80,32 @@ messages. Level 3 adds a hex dump of the network data.</P>
 
 <P>The default setting is <VAR>0</VAR>.</P>
 
+<H2 CLASS="title"><A NAME="DeviceURI">DeviceURI</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+DeviceURI "HP.*JetDirect.*" socket://%s:9100 socket://%s:9101 socket://%s:9102
+DeviceURI "HP.*" socket://%s
+DeviceURI "Acme.*Laser.*" lpd://%s/print
+DeviceURI "Xerox.*"
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>DeviceURI</CODE> directive specifies a regular expression
+(enclosed in double quotes) that is matched against the SNMP device
+description OID returned by a printer. If the description matches the
+regular expression, each device URI that follows the regular expression
+is listed by the backend, with any occurrences of <CODE>%s</CODE>
+replaced by the device's hostname or IP address. If no URIs are listed,
+the device is ignored.</P>
+
+<P>The <CODE>DeviceURI</CODE> directives are processed serially in
+the order specified in the <VAR>snmp.conf</VAR> file until a match
+is found.</P>
+
+
 <H2 CLASS="title"><A NAME="HostNameLookups">HostNameLookups</A></H2>
 
 <H3>Examples</H3>
index 9816e67437f842a05d83174d25528768e86dce77..be45bdd94c81bbb712367f888949adf51d560992 100644 (file)
@@ -38,7 +38,7 @@ Output-bin Attribute Extension", and "IPP/1.1: finishings
 'fold',' trim', and 'bale' attribute values extension"
 specifications.</p>
 
-<p>CUPS also provides 13 new operations and many new attributes
+<p>CUPS also provides 15 new operations and many new attributes
 to support multiple IPP printers and printer classes on a single
 host.</p>
 
@@ -321,6 +321,12 @@ summary='Supported Operations'>
        <td>0x400E</td>
        <td>Authenticate a job for printing.</td>
 </tr>
+<tr>
+       <td><a href='#CUPS_GET_PPD'>CUPS-Get-PPD</a></td>
+       <td>1.3</td>
+       <td>0x400F</td>
+       <td>Get a PPD file.</td>
+</tr>
 </tbody>
 </table></div>
 
@@ -1685,6 +1691,77 @@ CUPS-Authenticate-Job Response:
 
 </dl
 
+<h3 class='title'><span class='info'>CUPS 1.3</span><a name='CUPS_GET_PPD'>CUPS-Get-PPD Operation</a></h3>
+
+<p>The CUPS-Get-PPD operation (0x400F) gets a PPD file from the
+server. The PPD file can be specified using a <tt>ppd-name</tt>
+returned by <a href='#CUPS_GET_PPDS'><tt>CUPS-Get-PPDs</tt></a>
+or using the <tt>printer-uri</tt> for a queue.</p>
+
+<p>If the PPD file is found, <tt>successful-ok</tt> is returned with
+the PPD file following the response data.</p>
+
+<p>If the PPD file cannot be served by the local server because
+the <tt>printer-uri</tt> attribute points to an external printer,
+a <tt>cups-see-other</tt> status is returned with the correct
+URI to use.</p>
+
+<p>If the PPD file does not exist, <tt>client-error-not-found</tt> is
+returned.</p>
+
+<h4>CUPS-Get-PPD Request</h4>
+
+<p>The following group of attributes is supplied as part of the
+CUPS-Get-PPD request:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+       <dt>Natural Language and Character Set:
+
+       <dd>The "attributes-charset" and "attributes-natural-language"
+       attributes as described in section 3.1.4.1 of the IPP Model and
+       Semantics document.
+
+       <dt>"printer-uri" (uri)
+       <br><i>OR</i>
+       <br>"ppd-name" (name(255)):
+
+       <dd>The client MUST supply a printer URI or PPD name.
+
+</dl>
+
+<h4>CUPS-Get-PPD Response</h4>
+
+<p>The following group of attributes is sent as part of the
+CUPS-Get-PPD Response:
+
+<p>Group 1: Operation Attributes
+
+<dl>
+
+       <dt>Status Message:
+
+       <dd>The standard response status message.
+
+       <dt>Natural Language and Character Set:
+
+       <dd>The "attributes-charset" and "attributes-natural-language"
+       attributes as described in section 3.1.4.2 of the IPP Model and
+       Semantics document.
+
+       <dt>"printer-uri" (uri):
+
+       <dd>The printer that provides the actual PPD file when
+       the status code is cups-see-other (0x280)
+
+</dl>
+
+<p>If the status code is <tt>successful-ok</tt>, the PPD file follows
+the end of the IPP response.</p>
+
+
 <h2 class='title'><a name='ATTRIBUTES'>Attributes</a></h2>
 
 <p>CUPS provides many extension attributes to support multiple
@@ -1843,7 +1920,7 @@ for billing purposes.
 <p>The job-hold-until attribute specifies a hold time. In addition to the
 standard IPP/1.1 keyword names, CUPS supports name values of the form
 "HH:MM" and "HH:MM:SS" that specify a hold time. The hold time is in
-Greenwich Mean Time (GMT) and <i>not</i> in the local time zone. If the
+Universal Coordinated Time (UTC) and <i>not</i> in the local time zone. If the
 specified time is less than the current time, the job is held until the
 next day.
 
@@ -2064,15 +2141,19 @@ ShortNickName attributes are used instead.
 relative to the model directory. The forward slash (/) is used to
 delineate directories.
 
-<h4><a name="ppd-natural-language">ppd-natural-language (naturalLanguage)</a></h4>
+<h4><a name="ppd-natural-language">ppd-natural-language (1setOf naturalLanguage)</a></h4>
 
 <p>The ppd-natural-language attribute specifies the language encoding
 of the PPD file (the LanguageVersion attribute in the PPD file). If the
 language is unknown or undefined then "en" (English) is assumed.
 
-<h4><a name="ppd-product">ppd-product (text(127))</a></h4>
+<h4><a name="ppd-product">ppd-product (1setOf text(127))</a></h4>
+
+<p>The ppd-product attribute specifies the Product attribute values in the PPD file.
+
+<h4><a name="ppd-psversion">ppd-psversion (1setOf text(127))</a><span class="info">CUPS 1.3</span></h4>
 
-<p>The ppd-product attribute specifies the Product attribute value in the PPD file.
+<p>The ppd-product attribute specifies the PSVersion attribute values in the PPD file.
 
 
 <h3 class='title'><a name='PRINTER_ATTRIBUTES'>Printer Attributes</a></h3>
index 16c054544a116be07c0753355711978539996273..cf02272bc067cad6af3f8cb8b7b9ee24c682a53e 100644 (file)
@@ -8,7 +8,7 @@
 </head>
 <body>
 <!--
-  "$Id: spec-ppd.html 6252 2007-02-10 15:34:18Z mike $"
+  "$Id: spec-ppd.html 6457 2007-04-17 18:40:55Z mike $"
 
   CUPS PPD extensions specification for the Common UNIX Printing System (CUPS).
 
@@ -204,13 +204,13 @@ http://www.vendor.com/help"
 
 <p>This attribute describes which language localizations are
 included in the PPD. The "locale list" string is a space-delimited
-list of locale names ("en", "en_US", "fr_FR", etc.)</p>
+list of locale names ("en", "en_US", "fr_CA", etc.)</p>
 
 <p>Example:</p>
 
 <pre class='command'>
 <em>*% Specify Canadian, UK, and US English, and Candian and French French</em> 
-*cupsLanguages: "en_CA en_UK en_US fr_CA fr_FR"
+*cupsLanguages: "en_CA en_UK en_US fr_CA fr_CA"
 </pre>
 
 <h3>cupsManualCopies</h3>
@@ -575,7 +575,10 @@ languages by following the following additional rules:</p>
        <li>Localizations are specified using a locale prefix of
        the form "ll" or "ll_CC." where "ll" is the 2-letter ISO
        language code and "CC" is the 2-letter ISO country
-       code</li>
+       code<ul>
+               <li>A generic language translation ("ll") SHOULD be provided with country-specific differences ("ll_CC") provided only as needed</li>
+               <li>For historical reasons, the "zh" and "zh_CN" locales map to Simplified Chinese while the "zh_TW" locale maps to Traditional Chinese</li>
+       </ul></li>
 
        <li>Locale-specific translation strings MUST be encoded
        using UTF-8.</li>
@@ -612,17 +615,17 @@ in the PPD file for a given locale.</blockquote>
 <pre class='command'>
 *LanguageVersion: English
 *LanguageEncoding: ISOLatin1
-*cupsLanguages: "de_DE fr_FR"
+*cupsLanguages: "de fr_CA"
 *ModelName: "Foobar Laser 9999"
 
 <em>*% Localize ModelName for French and German</em>
-*fr_FR.Translation ModelName/La Foobar Laser 9999: ""
-*de_DE.Translation ModelName/Foobar LaserDrucken 9999: ""
+*fr_CA.Translation ModelName/La Foobar Laser 9999: ""
+*de.Translation ModelName/Foobar LaserDrucken 9999: ""
 
 *cupsIPPReason com.vendor-error/A serious error occurred: "/help/com.vendor/error.html"
 <em>*% Localize printer-state-reason for French and German</em>
-*fr_FR.cupsIPPReason com.vendor-error/Une erreur s&egrave;rieuse s'est produite: "/help/com.vendor/error.html"
-*de_DE.cupsIPPReason com.vendor-error/Eine ernste St&ouml;rung trat: "/help/com.vendor/error.html"
+*fr_CA.cupsIPPReason com.vendor-error/Une erreur s&egrave;rieuse s'est produite: "/help/com.vendor/error.html"
+*de.cupsIPPReason com.vendor-error/Eine ernste St&ouml;rung trat: "/help/com.vendor/error.html"
 
 ...
 
@@ -630,16 +633,16 @@ in the PPD file for a given locale.</blockquote>
 *OrderDependency: 10 AnySetup *InputSlot
 *DefaultInputSlot: Auto
 <em>*% Localize InputSlot for French and German</em>
-*fr_FR.Translation InputSlot/Papier source: ""
-*de_DE.Translation InputSlot/Papiereinzug: ""
+*fr_CA.Translation InputSlot/Papier source: ""
+*de.Translation InputSlot/Papiereinzug: ""
 *InputSlot Auto/Default: "&lt;&lt;/ManualFeed false&gt;&gt;setpagedevice"
 <em>*% Localize InputSlot=Auto for French and German</em>
-*fr_FR.InputSlot Auto/Par Defaut: ""
-*de_DE.InputSlot Auto/Standard: ""
+*fr_CA.InputSlot Auto/Par Defaut: ""
+*de.InputSlot Auto/Standard: ""
 *InputSlot Manual/Manual Feed: "&lt;&lt;/ManualFeed true&gt;&gt;setpagedevice"
 <em>*% Localize InputSlot=Manual for French and German</em>
-*fr_FR.InputSlot Manual/Manuel mecanisme de alimentation: ""
-*de_DE.InputSlot Manual/Manueller Einzug: ""
+*fr_CA.InputSlot Manual/Manuel mecanisme de alimentation: ""
+*de.InputSlot Manual/Manueller Einzug: ""
 *CloseUI: *InputSlot
 </pre>
 
index 149ddbf94ab29030bc456669f3b2bb0272a57579..1c3c6c09c85660a82c2b0a032b7d670f1cd07de6 100644 (file)
@@ -1,5 +1,5 @@
 .\"
-.\" "$Id: cupstestppd.man 5099 2006-02-13 02:46:10Z mike $"
+.\" "$Id: cupstestppd.man 6509 2007-05-03 22:58:41Z mike $"
 .\"
 .\"   cupstestppd man page for the Common UNIX Printing System (CUPS).
 .\"
 .\"       EMail: cups-info@cups.org
 .\"         WWW: http://www.cups.org
 .\"
-.TH cupstestppd 1 "Common UNIX Printing System" "12 February 2006" "Easy Software Products"
+.TH cupstestppd 1 "Common UNIX Printing System" "3 May 2007" "Easy Software Products"
 .SH NAME
 cupstestppd \- test conformance of ppd files
 .SH SYNOPSIS
 .B cupstestppd
-[ -q ] [-r] [ -v[v] ] filename.ppd[.gz] [ ... filenameN.ppd[.gz] ]
+[ -R
+.I rootdir
+] [ -W
+.I category
+] [ -q ] [-r] [ -v[v] ] filename.ppd[.gz] [ ... filenameN.ppd[.gz] ]
 .br
 .B cupstestppd
-[ -q ] [-r] [ -v[v] ] -
+[ -R
+.I rootdir
+] [ -W
+.I category
+] [ -q ] [-r] [ -v[v] ] -
 .SH DESCRIPTION
 \fIcupstestppd\fR tests the conformance of PPD files to the
 Adobe PostScript Printer Description file format specification
@@ -43,6 +51,35 @@ on the standard input.
 .SH OPTIONS
 \fIcupstestppd\fR supports the following options:
 .TP 5
+-R rootdir
+.br
+Specifies an alternate root directory for the filter, pre-filter,
+and other support file checks.
+.TP 5
+-W constraints
+.br
+Report all UIConstraint errors as warnings.
+.TP 5
+-W defaults
+.br
+Except for size-related options, report all default option errors as warnings.
+.TP 5
+-W filters
+.br
+Report all filter errors as warnings.
+.TP 5
+-W translations
+.br
+Report all translation errors as warnings.
+.TP 5
+-W all
+.br
+Report all of the previous errors as warnings.
+.TP 5
+-W none
+.br
+Report all of the previous errors as errors.
+.TP 5
 -q
 .br
 Specifies that no information should be displayed.
@@ -109,7 +146,7 @@ http://localhost:631/help
 .br
 Adobe PostScript Printer Description File Format Specification, Version 4.3.
 .SH COPYRIGHT
-Copyright 1997-2006 by Easy Software Products, All Rights Reserved.
+Copyright 1997-2007 by Easy Software Products, All Rights Reserved.
 .\"
-.\" End of "$Id: cupstestppd.man 5099 2006-02-13 02:46:10Z mike $".
+.\" End of "$Id: cupstestppd.man 6509 2007-05-03 22:58:41Z mike $".
 .\"
index 2b6ced2b5cd73c56d16a645cfe72fc5c549143f1..144038775cb8b70705ec88be0818d2118ff7b670 100644 (file)
@@ -1,5 +1,5 @@
 #
-# "$Id: cups.list.in 6431 2007-04-02 14:31:49Z mike $"
+# "$Id: cups.list.in 6480 2007-04-27 18:53:20Z mike $"
 #
 #   ESP Package Manager (EPM) file list for the Common UNIX Printing
 #   System (CUPS).
@@ -434,7 +434,7 @@ d 0755 root sys $DATADIR/model -
 f 0644 root sys $DATADIR/model ppd/*.ppd
 
 d 0755 root sys $DATADIR/templates -
-c 0644 root sys $DATADIR/templates templates/*.tmpl
+f 0644 root sys $DATADIR/templates templates/*.tmpl
 
 # Japanese template files
 %subpackage de
@@ -637,6 +637,8 @@ f 0644 root sys /System/Library/LaunchDaemons/org.cups.cupsd.plist init/org.cups
 %postinstall <<EOF
 rm -f /System/Library/StartupItems/PrintingServices/PrintingServices
 launchctl unload /System/Library/LaunchDaemons/org.cups.cupsd.plist || exit 0
+killall cupsd
+sleep 1
 launchctl load /System/Library/LaunchDaemons/org.cups.cupsd.plist
 EOF
 %subpackage lpd
@@ -657,5 +659,5 @@ f 0644 root sys $XINETD/cups-lpd init/cups-lpd
 %subpackage
 
 #
-# End of "$Id: cups.list.in 6431 2007-04-02 14:31:49Z mike $".
+# End of "$Id: cups.list.in 6480 2007-04-27 18:53:20Z mike $".
 #
index 15d371fda4908d4a7c051ea9c3e4fb44acd3f356..18b893c37d256a153279df3c0273241775a2ed12 100644 (file)
@@ -2511,17 +2511,20 @@ GBool PSOutputDev::startPage(int pageNum, GfxState *state) {
       landscape = gFalse;
     } else {
       rotate = (360 - state->getRotate()) % 360;
+
+      fprintf(stderr, "DEBUG: Page rotate=%d, width=%d, height=%d, imgWidth=%d, imgHeight=%d\n",
+              state->getRotate(), width, height, imgWidth, imgHeight);
+
+      rotate = (360 - state->getRotate()) % 360;
       if (rotate == 0 || rotate == 180) {
-       if ((width > height && imgWidth < imgHeight) ||
-           (height > width && imgHeight < imgWidth)) {
+       if (width > height && width > imgWidth) {
          rotate += 90;
          landscape = gTrue;
        } else {
          landscape = gFalse;
        }
       } else { // rotate == 90 || rotate == 270
-       if ((width > height && imgWidth < imgHeight) ||
-           (height > width && imgHeight < imgWidth)) {
+       if (height > width && height > imgWidth) {
          rotate = 270 - rotate;
          landscape = gTrue;
        } else {
@@ -2529,6 +2532,7 @@ GBool PSOutputDev::startPage(int pageNum, GfxState *state) {
        }
       }
     }
+
     writePSFmt("%%%%PageOrientation: %s\n",
               landscape ? "Landscape" : "Portrait");
     writePS("pdfStartPage\n");
index 71ca92880c0efcffc554362133b7ec9d07d444f9..68439f30ed2c3300440571c1b4331a39f9149ebe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: client.c 6383 2007-03-21 20:01:20Z mike $"
+ * "$Id: client.c 6504 2007-05-02 00:14:56Z mike $"
  *
  *   Client routines for the Common UNIX Printing System (CUPS) scheduler.
  *
@@ -2531,10 +2531,10 @@ cupsdWriteClient(cupsd_client_t *con)   /* I - Client connection */
 
 #ifdef DEBUG
   cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdWriteClient(con=%p) %d response=%p, file=%d "
+                  "cupsdWriteClient(con=%p) %d response=%p(%d), file=%d "
                  "pipe_pid=%d state=%d",
-                  con, con->http.fd, con->response, con->file, con->pipe_pid,
-                 con->http.state);
+                  con, con->http.fd, con->response, con->response->state,
+                 con->file, con->pipe_pid, con->http.state);
 #endif /* DEBUG */
 
   if (con->http.state != HTTP_GET_SEND &&
@@ -2562,10 +2562,11 @@ cupsdWriteClient(cupsd_client_t *con)   /* I - Client connection */
     con->file_ready = 0;
   }
 
-  if (con->response)
+  if (con->response && con->response->state != IPP_DATA)
   {
     ipp_state = ippWrite(HTTP(con), con->response);
-    bytes     = ipp_state != IPP_ERROR && ipp_state != IPP_DATA;
+    bytes     = ipp_state != IPP_ERROR &&
+                (con->file >= 0 || ipp_state != IPP_DATA);
   }
   else if ((bytes = read(con->file, buf, sizeof(buf) - 1)) > 0)
   {
@@ -3581,9 +3582,9 @@ is_cgi(cupsd_client_t *con,               /* I - Client connection */
     cupsdSetString(&con->command, CUPS_JAVA);
 
     if (options)
-      cupsdSetStringf(&con->options, "%s %s", filename, options);
+      cupsdSetStringf(&con->options, " %s %s", filename, options);
     else
-      cupsdSetString(&con->options, filename);
+      cupsdSetStringf(&con->options, " %s", filename);
 
     cupsdLogMessage(CUPSD_LOG_DEBUG2,
                     "is_cgi: Returning 1 with command=\"%s\" and options=\"%s\"",
@@ -3602,9 +3603,9 @@ is_cgi(cupsd_client_t *con,               /* I - Client connection */
     cupsdSetString(&con->command, CUPS_PERL);
 
     if (options)
-      cupsdSetStringf(&con->options, "%s %s", filename, options);
+      cupsdSetStringf(&con->options, " %s %s", filename, options);
     else
-      cupsdSetString(&con->options, filename);
+      cupsdSetStringf(&con->options, " %s", filename);
 
     cupsdLogMessage(CUPSD_LOG_DEBUG2,
                     "is_cgi: Returning 1 with command=\"%s\" and options=\"%s\"",
@@ -3623,9 +3624,9 @@ is_cgi(cupsd_client_t *con,               /* I - Client connection */
     cupsdSetString(&con->command, CUPS_PHP);
 
     if (options)
-      cupsdSetStringf(&con->options, "%s %s", filename, options);
+      cupsdSetStringf(&con->options, " %s %s", filename, options);
     else
-      cupsdSetString(&con->options, filename);
+      cupsdSetStringf(&con->options, " %s", filename);
 
     cupsdLogMessage(CUPSD_LOG_DEBUG2,
                     "is_cgi: Returning 1 with command=\"%s\" and options=\"%s\"",
@@ -3644,9 +3645,9 @@ is_cgi(cupsd_client_t *con,               /* I - Client connection */
     cupsdSetString(&con->command, CUPS_PYTHON);
 
     if (options)
-      cupsdSetStringf(&con->options, "%s %s", filename, options);
+      cupsdSetStringf(&con->options, " %s %s", filename, options);
     else
-      cupsdSetString(&con->options, filename);
+      cupsdSetStringf(&con->options, " %s", filename);
 
     cupsdLogMessage(CUPSD_LOG_DEBUG2,
                     "is_cgi: Returning 1 with command=\"%s\" and options=\"%s\"",
@@ -4165,8 +4166,9 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */
   int          envc;                   /* Number of environment variables */
   char         argbuf[10240],          /* Argument buffer */
                *argv[100],             /* Argument strings */
-               *envp[MAX_ENV + 18];    /* Environment variables */
-  char         content_length[1024],   /* CONTENT_LENGTH environment variable */
+               *envp[MAX_ENV + 20];    /* Environment variables */
+  char         auth_type[256],         /* AUTH_TYPE environment variable */
+               content_length[1024],   /* CONTENT_LENGTH environment variable */
                content_type[1024],     /* CONTENT_TYPE environment variable */
                http_cookie[32768],     /* HTTP_COOKIE environment variable */
                http_referer[1024],     /* HTTP_REFERER environment variable */
@@ -4176,6 +4178,7 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */
                remote_addr[1024],      /* REMOTE_ADDR environment variable */
                remote_host[1024],      /* REMOTE_HOST environment variable */
                remote_user[1024],      /* REMOTE_USER environment variable */
+               script_filename[1024],  /* SCRIPT_FILENAME environment variable */
                script_name[1024],      /* SCRIPT_NAME environment variable */
                server_name[1024],      /* SERVER_NAME environment variable */
                server_port[1024];      /* SERVER_PORT environment variable */
@@ -4228,6 +4231,9 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */
   {
     commptr      = argbuf;
     path_info[0] = '\0';
+
+    if (*commptr == ' ')
+      commptr ++;
   }
 
   cupsdLogMessage(CUPSD_LOG_INFO, "commptr=\"%s\"", commptr);
@@ -4302,6 +4308,17 @@ pipe_command(cupsd_client_t *con,        /* I - Client connection */
   * Setup the environment variables as needed...
   */
 
+  if (con->username[0])
+  {
+    snprintf(auth_type, sizeof(auth_type), "AUTH_TYPE=%s",
+             httpGetField(HTTP(con), HTTP_FIELD_AUTHORIZATION));
+
+    if ((uriptr = strchr(auth_type + 10, ' ')) != NULL)
+      *uriptr = '\0';
+  }
+  else
+    auth_type[0] = '\0';
+
   if (con->language)
     snprintf(lang, sizeof(lang), "LANG=%s.UTF-8", con->language->language);
   else
@@ -4318,6 +4335,9 @@ pipe_command(cupsd_client_t *con, /* I - Client connection */
   if ((uriptr = strchr(script_name, '?')) != NULL)
     *uriptr = '\0';
 
+  snprintf(script_filename, sizeof(script_filename), "SCRIPT_FILENAME=%s%s",
+           DocumentRoot, script_name + 12);
+
   sprintf(server_port, "SERVER_PORT=%d", con->serverport);
 
   snprintf(server_name, sizeof(server_name), "SERVER_NAME=%s",
@@ -4325,13 +4345,18 @@ pipe_command(cupsd_client_t *con,       /* I - Client connection */
 
   envc = cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0])));
 
+  if (auth_type[0])
+    envp[envc ++] = auth_type;
+
   envp[envc ++] = lang;
   envp[envc ++] = "REDIRECT_STATUS=1";
+  envp[envc ++] = "GATEWAY_INTERFACE=CGI/1.1";
   envp[envc ++] = server_name;
   envp[envc ++] = server_port;
   envp[envc ++] = remote_addr;
   envp[envc ++] = remote_host;
   envp[envc ++] = script_name;
+  envp[envc ++] = script_filename;
 
   if (path_info[0])
     envp[envc ++] = path_info;
@@ -4537,5 +4562,5 @@ write_pipe(cupsd_client_t *con)           /* I - Client connection */
 
 
 /*
- * End of "$Id: client.c 6383 2007-03-21 20:01:20Z mike $".
+ * End of "$Id: client.c 6504 2007-05-02 00:14:56Z mike $".
  */
index de1fb670478d8f35db855f2679ac09c60cf3699d..82061b7bb793322a53a04ebd3808523b2e9bc85c 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * "$Id: client.h 6383 2007-03-21 20:01:20Z mike $"
+ * "$Id: client.h 6503 2007-05-01 23:06:44Z mike $"
  *
  *   Client definitions for the Common UNIX Printing System (CUPS) scheduler.
  *
- *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
  *   property of Easy Software Products and are protected by Federal
@@ -138,5 +138,5 @@ extern void cupsdWriteClient(cupsd_client_t *con);
 
 
 /*
- * End of "$Id: client.h 6383 2007-03-21 20:01:20Z mike $".
+ * End of "$Id: client.h 6503 2007-05-01 23:06:44Z mike $".
  */
index ad463acb690b19e8db277dfb7bce2f8ed91772a6..5fd8f10cfcd04a0d02c52fe92f11e8d85c2f92d6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: conf.c 6436 2007-04-02 23:24:02Z mike $"
+ * "$Id: conf.c 6505 2007-05-03 17:44:22Z mike $"
  *
  *   Configuration routines for the Common UNIX Printing System (CUPS).
  *
@@ -23,9 +23,9 @@
  *
  * Contents:
  *
- *   cupsdReadConfiguration() - Read the cupsd.conf file.
- *   check_permissions()      - Fix the mode and ownership of a file or
+ *   cupsdCheckPermissions()  - Fix the mode and ownership of a file or
  *                              directory.
+ *   cupsdReadConfiguration() - Read the cupsd.conf file.
  *   get_address()            - Get an address + port number from a line.
  *   get_addr_and_mask()      - Get an IP address and netmask.
  *   parse_aaa()              - Parse authentication, authorization, and
 #include <stdarg.h>
 #include <grp.h>
 #include <sys/utsname.h>
+#include <syslog.h>
 #include <cups/dir.h>
 
-#ifdef HAVE_VSYSLOG
-#  include <syslog.h>
-#endif /* HAVE_VSYSLOG */
-
 
 /*
  * Possibly missing network definitions...
@@ -197,10 +194,6 @@ static unsigned            zeros[4] =
 /*
  * Local functions...
  */
-static int             check_permissions(const char *filename,
-                                         const char *suffix, int mode,
-                                         int user, int group, int is_dir,
-                                         int create_dir);
 static http_addrlist_t *get_address(const char *value, int defport);
 static int             get_addr_and_mask(const char *value, unsigned *ip,
                                          unsigned *mask);
@@ -213,6 +206,138 @@ static int                read_location(cups_file_t *fp, char *name, int linenum);
 static int             read_policy(cups_file_t *fp, char *name, int linenum);
 
 
+/*
+ * 'cupsdCheckPermissions()' - Fix the mode and ownership of a file or directory.
+ */
+
+int                                    /* O - 0 on success, -1 on error, 1 on warning */
+cupsdCheckPermissions(
+    const char *filename,              /* I - File/directory name */
+    const char *suffix,                        /* I - Additional file/directory name */
+    int        mode,                   /* I - Permissions */
+    int        user,                   /* I - Owner */
+    int        group,                  /* I - Group */
+    int        is_dir,                 /* I - 1 = directory, 0 = file */
+    int        create_dir)             /* I - 1 = create directory, -1 = create w/o logging, 0 = not */
+{
+  int          dir_created = 0;        /* Did we create a directory? */
+  char         pathname[1024];         /* File name with prefix */
+  struct stat  fileinfo;               /* Stat buffer */
+
+
+ /*
+  * Prepend the given root to the filename before testing it...
+  */
+
+  if (suffix)
+  {
+    snprintf(pathname, sizeof(pathname), "%s/%s", filename, suffix);
+    filename = pathname;
+  }
+
+ /*
+  * See if we can stat the file/directory...
+  */
+
+  if (stat(filename, &fileinfo))
+  {
+    if (errno == ENOENT && create_dir)
+    {
+      if (create_dir > 0)
+       cupsdLogMessage(CUPSD_LOG_DEBUG, "Creating missing directory \"%s\"",
+                       filename);
+
+      if (mkdir(filename, mode))
+      {
+        if (create_dir > 0)
+         cupsdLogMessage(CUPSD_LOG_ERROR,
+                         "Unable to create directory \"%s\" - %s", filename,
+                         strerror(errno));
+        else
+         syslog(LOG_ERR, "Unable to create directory \"%s\" - %s", filename,
+                strerror(errno));
+
+        return (-1);
+      }
+
+      dir_created = 1;
+    }
+    else
+      return (create_dir ? -1 : 1);
+  }
+
+ /*
+  * Make sure it's a regular file...
+  */
+
+  if (!dir_created && !is_dir && !S_ISREG(fileinfo.st_mode))
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR, "\"%s\" is not a regular file!", filename);
+    return (-1);
+  }
+
+  if (!dir_created && is_dir && !S_ISDIR(fileinfo.st_mode))
+  {
+    if (create_dir >= 0)
+      cupsdLogMessage(CUPSD_LOG_ERROR, "\"%s\" is not a directory!", filename);
+    else
+      syslog(LOG_ERR, "\"%s\" is not a directory!", filename);
+
+    return (-1);
+  }
+
+ /*
+  * Fix owner, group, and mode as needed...
+  */
+
+  if (dir_created || fileinfo.st_uid != user || fileinfo.st_gid != group)
+  {
+    if (create_dir >= 0)
+      cupsdLogMessage(CUPSD_LOG_DEBUG, "Repairing ownership of \"%s\"",
+                      filename);
+
+    if (chown(filename, user, group) && !getuid())
+    {
+      if (create_dir >= 0)
+       cupsdLogMessage(CUPSD_LOG_ERROR,
+                       "Unable to change ownership of \"%s\" - %s", filename,
+                       strerror(errno));
+      else
+       syslog(LOG_ERR, "Unable to change ownership of \"%s\" - %s", filename,
+              strerror(errno));
+
+      return (1);
+    }
+  }
+
+  if (dir_created || (fileinfo.st_mode & 07777) != mode)
+  {
+    if (create_dir >= 0)
+      cupsdLogMessage(CUPSD_LOG_DEBUG, "Repairing access permissions of \"%s\"",
+                     filename);
+
+    if (chmod(filename, mode))
+    {
+      if (create_dir >= 0)
+       cupsdLogMessage(CUPSD_LOG_ERROR,
+                       "Unable to change permissions of \"%s\" - %s", filename,
+                       strerror(errno));
+      else
+       syslog(LOG_ERR, "Unable to change permissions of \"%s\" - %s", filename,
+              strerror(errno));
+
+      return (1);
+    }
+  }
+
+ /*
+  * Everything is OK...
+  */
+
+  return (0);
+}
+
+
 /*
  * 'cupsdReadConfiguration()' - Read the cupsd.conf file.
  */
@@ -658,20 +783,28 @@ cupsdReadConfiguration(void)
   * writable by the user and group in the cupsd.conf file...
   */
 
-  if (check_permissions(CacheDir, NULL, 0775, RunUser, Group, 1, 1) < 0 ||
-      check_permissions(StateDir, NULL, 0755, RunUser, Group, 1, 1) < 0 ||
-      check_permissions(StateDir, "certs", RunUser ? 0711 : 0511, User,
-                       SystemGroupIDs[0], 1, 1) < 0 ||
-      check_permissions(ServerRoot, NULL, 0755, RunUser, Group, 1, 0) < 0 ||
-      check_permissions(ServerRoot, "ppd", 0755, RunUser, Group, 1, 1) < 0 ||
-      check_permissions(ServerRoot, "ssl", 0700, RunUser, Group, 1, 0) < 0 ||
-      check_permissions(ServerRoot, "cupsd.conf", ConfigFilePerm, RunUser,
-                        Group, 0, 0) < 0 ||
-      check_permissions(ServerRoot, "classes.conf", 0600, RunUser, Group,
-                        0, 0) < 0 ||
-      check_permissions(ServerRoot, "printers.conf", 0600, RunUser, Group,
-                        0, 0) < 0 ||
-      check_permissions(ServerRoot, "passwd.md5", 0600, User, Group, 0, 0) < 0)
+  if (cupsdCheckPermissions(RequestRoot, NULL, 0710, RunUser,
+                           Group, 1, 1) < 0 ||
+      cupsdCheckPermissions(CacheDir, NULL, 0775, RunUser,
+                           Group, 1, 1) < 0 ||
+      cupsdCheckPermissions(StateDir, NULL, 0755, RunUser,
+                           Group, 1, 1) < 0 ||
+      cupsdCheckPermissions(StateDir, "certs", RunUser ? 0711 : 0511, User,
+                           SystemGroupIDs[0], 1, 1) < 0 ||
+      cupsdCheckPermissions(ServerRoot, NULL, 0755, RunUser, 
+                           Group, 1, 0) < 0 ||
+      cupsdCheckPermissions(ServerRoot, "ppd", 0755, RunUser,
+                           Group, 1, 1) < 0 ||
+      cupsdCheckPermissions(ServerRoot, "ssl", 0700, RunUser,
+                           Group, 1, 0) < 0 ||
+      cupsdCheckPermissions(ServerRoot, "cupsd.conf", ConfigFilePerm, RunUser,
+                           Group, 0, 0) < 0 ||
+      cupsdCheckPermissions(ServerRoot, "classes.conf", 0600, RunUser,
+                           Group, 0, 0) < 0 ||
+      cupsdCheckPermissions(ServerRoot, "printers.conf", 0600, RunUser,
+                           Group, 0, 0) < 0 ||
+      cupsdCheckPermissions(ServerRoot, "passwd.md5", 0600, User,
+                           Group, 0, 0) < 0)
     return (0);
 
  /*
@@ -710,13 +843,9 @@ cupsdReadConfiguration(void)
   }
 
  /*
-  * Make sure the request and temporary directories have the right
-  * permissions...
+  * Make sure the temporary directory has the right permissions...
   */
 
-  if (check_permissions(RequestRoot, NULL, 0710, RunUser, Group, 1, 1) < 0)
-    return (0);
-
   if (!strncmp(TempDir, RequestRoot, strlen(RequestRoot)) ||
       access(TempDir, 0))
   {
@@ -725,7 +854,7 @@ cupsdReadConfiguration(void)
     * is under the spool directory or does not exist...
     */
 
-    if (check_permissions(TempDir, NULL, 01770, RunUser, Group, 1, 1) < 0)
+    if (cupsdCheckPermissions(TempDir, NULL, 01770, RunUser, Group, 1, 1) < 0)
       return (0);
   }
 
@@ -1132,114 +1261,6 @@ cupsdReadConfiguration(void)
 }
 
 
-/*
- * 'check_permissions()' - Fix the mode and ownership of a file or directory.
- */
-
-static int                             /* O - 0 on success, -1 on error, 1 on warning */
-check_permissions(const char *filename,        /* I - File/directory name */
-                  const char *suffix,  /* I - Additional file/directory name */
-                  int        mode,     /* I - Permissions */
-                 int        user,      /* I - Owner */
-                 int        group,     /* I - Group */
-                 int        is_dir,    /* I - 1 = directory, 0 = file */
-                 int        create_dir)/* I - 1 = create directory, 0 = not */
-{
-  int          dir_created = 0;        /* Did we create a directory? */
-  char         pathname[1024];         /* File name with prefix */
-  struct stat  fileinfo;               /* Stat buffer */
-
-
- /*
-  * Prepend the given root to the filename before testing it...
-  */
-
-  if (suffix)
-  {
-    snprintf(pathname, sizeof(pathname), "%s/%s", filename, suffix);
-    filename = pathname;
-  }
-
- /*
-  * See if we can stat the file/directory...
-  */
-
-  if (stat(filename, &fileinfo))
-  {
-    if (errno == ENOENT && create_dir)
-    {
-      cupsdLogMessage(CUPSD_LOG_DEBUG, "Creating missing directory \"%s\"",
-                      filename);
-
-      if (mkdir(filename, mode))
-      {
-        cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "Unable to create directory \"%s\" - %s", filename,
-                       strerror(errno));
-        return (-1);
-      }
-
-      dir_created = 1;
-    }
-    else
-      return (create_dir ? -1 : 1);
-  }
-
- /*
-  * Make sure it's a regular file...
-  */
-
-  if (!dir_created && !is_dir && !S_ISREG(fileinfo.st_mode))
-  {
-    cupsdLogMessage(CUPSD_LOG_ERROR, "\"%s\" is not a regular file!", filename);
-    return (-1);
-  }
-
-  if (!dir_created && is_dir && !S_ISDIR(fileinfo.st_mode))
-  {
-    cupsdLogMessage(CUPSD_LOG_ERROR, "\"%s\" is not a directory!", filename);
-    return (-1);
-  }
-
- /*
-  * Fix owner, group, and mode as needed...
-  */
-
-  if (dir_created || fileinfo.st_uid != user || fileinfo.st_gid != group)
-  {
-    cupsdLogMessage(CUPSD_LOG_DEBUG, "Repairing ownership of \"%s\"", filename);
-
-    if (chown(filename, user, group) && !getuid())
-    {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "Unable to change ownership of \"%s\" - %s", filename,
-                     strerror(errno));
-      return (1);
-    }
-  }
-
-  if (dir_created || (fileinfo.st_mode & 07777) != mode)
-  {
-    cupsdLogMessage(CUPSD_LOG_DEBUG, "Repairing access permissions of \"%s\"",
-                    filename);
-
-    if (chmod(filename, mode))
-    {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "Unable to change permissions of \"%s\" - %s", filename,
-                     strerror(errno));
-      return (1);
-    }
-  }
-
- /*
-  * Everything is OK...
-  */
-
-  return (0);
-}
-
-
 /*
  * 'get_address()' - Get an address + port number from a line.
  */
@@ -3352,5 +3373,5 @@ read_policy(cups_file_t *fp,              /* I - Configuration file */
 
 
 /*
- * End of "$Id: conf.c 6436 2007-04-02 23:24:02Z mike $".
+ * End of "$Id: conf.c 6505 2007-05-03 17:44:22Z mike $".
  */
index 6bb223ecba11fa362c15f581ba009075422bbc8f..87eb94ebaef79ad6fa430454bf9aea28b93feed6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: conf.h 6436 2007-04-02 23:24:02Z mike $"
+ * "$Id: conf.h 6490 2007-04-30 18:09:30Z mike $"
  *
  *   Configuration file definitions for the Common UNIX Printing System (CUPS)
  *   scheduler.
@@ -218,8 +218,11 @@ VAR char           *SystemGroupAuthKey     VALUE(NULL);
  * Prototypes...
  */
 
+extern int     cupsdCheckPermissions(const char *filename,
+                                     const char *suffix, int mode,
+                                     int user, int group, int is_dir,
+                                     int create_dir);
 extern char    *cupsdGetDateTime(time_t t);
-extern int     cupsdReadConfiguration(void);
 #ifdef HAVE_GSSAPI
 extern int     cupsdLogGSSMessage(int level, int major_status,
                                   int minor_status,
@@ -232,8 +235,9 @@ __attribute__ ((__format__ (__printf__, 2, 3)))
 ;
 extern int     cupsdLogPage(cupsd_job_t *job, const char *page);
 extern int     cupsdLogRequest(cupsd_client_t *con, http_status_t code);
+extern int     cupsdReadConfiguration(void);
 
 
 /*
- * End of "$Id: conf.h 6436 2007-04-02 23:24:02Z mike $".
+ * End of "$Id: conf.h 6490 2007-04-30 18:09:30Z mike $".
  */
index e2898ad292c5f7e727d7adf4ca2debab3a499f0e..1a7a3931daee6e48d1741f68100283e3c203e000 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: cups-driverd.c 6377 2007-03-21 07:17:11Z mike $"
+ * "$Id: cups-driverd.c 6508 2007-05-03 20:07:14Z mike $"
  *
  *   PPD/driver support for the Common UNIX Printing System (CUPS).
  *
@@ -32,6 +32,7 @@
  *   cat_ppd()       - Copy a PPD file to stdout.
  *   compare_names() - Compare PPD filenames for sorting.
  *   compare_ppds()  - Compare PPD file make and model names for sorting.
+ *   free_array()    - Free an array of strings.
  *   list_ppds()     - List PPD files.
  *   load_ppds()     - Load PPD files recursively.
  *   load_drivers()  - Load driver-generated PPD files.
 extern cups_encoding_t _ppdGetEncoding(const char *name);
 
 
+/*
+ * Constants...
+ */
+
+#define PPD_SYNC       0x50504433      /* Sync word for ppds.dat (PPD3) */
+#define PPD_MAX_LANG   32              /* Maximum languages */
+#define PPD_MAX_PROD   8               /* Maximum products */
+#define PPD_MAX_VERS   8               /* Maximum versions */
+
+
 /*
  * PPD information structures...
  */
@@ -61,14 +72,17 @@ typedef struct                              /**** PPD record ****/
 {
   time_t       mtime;                  /* Modification time */
   size_t       size;                   /* Size in bytes */
-  char         name[512 - sizeof(time_t) - sizeof(size_t)],
-                                       /* PPD name */
-               natural_language[6],    /* LanguageVersion */
-               product[122],           /* Product */
+  char         name[512],              /* PPD name */
+               languages[PPD_MAX_LANG][6],
+                                       /* LanguageVersion/cupsLanguages */
+               products[PPD_MAX_PROD][128],
+                                       /* Product strings */
+               psversions[PPD_MAX_VERS][32],
+                                       /* PSVersion strings */
                make[128],              /* Manufacturer */
                make_and_model[128],    /* NickName/ModelName */
                device_id[128];         /* IEEE 1284 Device ID */
-} ppd_rec_t;
+} ppd_rec_t; 
 
 typedef struct                         /**** In-memory record ****/
 {
@@ -92,18 +106,20 @@ int                ChangedPPD;             /* Did we change the PPD database? */
  * Local functions...
  */
 
-static ppd_info_t      *add_ppd(const char *name, const char *natural_language,
+static ppd_info_t      *add_ppd(const char *name, const char *language,
                                 const char *make, const char *make_and_model,
                                 const char *device_id, const char *product,
-                                time_t mtime, size_t size);
-static int             cat_ppd(const char *name);
+                                const char *psversion, time_t mtime,
+                                size_t size);
+static int             cat_ppd(const char *name, int request_id);
 static int             compare_names(const ppd_info_t *p0,
                                      const ppd_info_t *p1);
 static int             compare_ppds(const ppd_info_t *p0,
                                     const ppd_info_t *p1);
+static void            free_array(cups_array_t *a);
 static int             list_ppds(int request_id, int limit, const char *opt);
 static int             load_drivers(void);
-static int             load_ppds(const char *d, const char *p);
+static int             load_ppds(const char *d, const char *p, int descend);
 
 
 /*
@@ -123,12 +139,15 @@ main(int  argc,                           /* I - Number of command-line args */
   */
 
   if (argc == 3 && !strcmp(argv[1], "cat"))
-    return (cat_ppd(argv[2]));
+    return (cat_ppd(argv[2], 0));
+  else if (argc == 4 && !strcmp(argv[1], "get"))
+    return (cat_ppd(argv[3], atoi(argv[2])));
   else if (argc == 5 && !strcmp(argv[1], "list"))
     return (list_ppds(atoi(argv[2]), atoi(argv[3]), argv[4]));
   else
   {
     fputs("Usage: cups-driverd cat ppd-name\n", stderr);
+    fputs("Usage: cups-driverd get request_id ppd-name\n", stderr);
     fputs("Usage: cups-driverd list request_id limit options\n", stderr);
     return (1);
   }
@@ -141,11 +160,12 @@ main(int  argc,                           /* I - Number of command-line args */
 
 static ppd_info_t *                    /* O - PPD */
 add_ppd(const char *name,              /* I - PPD name */
-        const char *natural_language,  /* I - Language(s) */
+        const char *language,          /* I - LanguageVersion */
         const char *make,              /* I - Manufacturer */
        const char *make_and_model,     /* I - NickName/ModelName */
        const char *device_id,          /* I - 1284DeviceID */
        const char *product,            /* I - Product */
+       const char *psversion,          /* I - PSVersion */
         time_t     mtime,              /* I - Modification time */
        size_t     size)                /* I - File size */
 {
@@ -172,7 +192,8 @@ add_ppd(const char *name,           /* I - PPD name */
 
     if (ppd == NULL)
     {
-      fprintf(stderr, "ERROR: [cups-driverd] Ran out of memory for %d PPD files!\n",
+      fprintf(stderr,
+              "ERROR: [cups-driverd] Ran out of memory for %d PPD files!\n",
              AllocPPDs);
       return (NULL);
     }
@@ -194,9 +215,11 @@ add_ppd(const char *name,          /* I - PPD name */
   ppd->record.size  = size;
 
   strlcpy(ppd->record.name, name, sizeof(ppd->record.name));
-  strlcpy(ppd->record.natural_language, natural_language,
-          sizeof(ppd->record.natural_language));
-  strlcpy(ppd->record.product, product, sizeof(ppd->record.product));
+  strlcpy(ppd->record.languages[0], language,
+          sizeof(ppd->record.languages[0]));
+  strlcpy(ppd->record.products[0], product, sizeof(ppd->record.products[0]));
+  strlcpy(ppd->record.psversions[0], psversion,
+          sizeof(ppd->record.psversions[0]));
   strlcpy(ppd->record.make, make, sizeof(ppd->record.make));
   strlcpy(ppd->record.make_and_model, make_and_model,
           sizeof(ppd->record.make_and_model));
@@ -207,7 +230,8 @@ add_ppd(const char *name,           /* I - PPD name */
   * Foomatic drivers...
   */
 
-  if ((recommended = strstr(ppd->record.make_and_model, " (recommended)")) != NULL)
+  if ((recommended = strstr(ppd->record.make_and_model,
+                            " (recommended)")) != NULL)
     *recommended = '\0';
 
  /*
@@ -223,11 +247,13 @@ add_ppd(const char *name,         /* I - PPD name */
  */
 
 static int                             /* O - Exit code */
-cat_ppd(const char *name)              /* I - PPD name */
+cat_ppd(const char *name,              /* I - PPD name */
+        int        request_id)         /* I - Request ID for response? */
 {
   char         scheme[256],            /* Scheme from PPD name */
                *sptr;                  /* Pointer into scheme */
   char         line[1024];             /* Line/filename */
+  char         message[2048];          /* status-message */
 
 
  /*
@@ -252,6 +278,8 @@ cat_ppd(const char *name)           /* I - PPD name */
   else
     scheme[0] = '\0';
 
+  puts("Content-Type: application/ipp\n");
+
   if (scheme[0])
   {
    /*
@@ -273,6 +301,21 @@ cat_ppd(const char *name)          /* I - PPD name */
 
       fprintf(stderr, "ERROR: [cups-driverd] Unable to access \"%s\" - %s\n",
               line, strerror(errno));
+
+      if (request_id > 0)
+      {
+        snprintf(message, sizeof(message), "Unable to access \"%s\" - %s",
+                line, strerror(errno));
+
+       cupsdSendIPPHeader(IPP_NOT_FOUND, request_id);
+       cupsdSendIPPGroup(IPP_TAG_OPERATION);
+       cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+       cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language",
+                          "en-US");
+        cupsdSendIPPString(IPP_TAG_TEXT, "status-message", message);
+        cupsdSendIPPTrailer();
+      }
+
       return (1);
     }
 
@@ -280,6 +323,16 @@ cat_ppd(const char *name)          /* I - PPD name */
     * Yes, let it cat the PPD file...
     */
 
+    if (request_id)
+    {
+      cupsdSendIPPHeader(IPP_OK, request_id);
+      cupsdSendIPPGroup(IPP_TAG_OPERATION);
+      cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+      cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language",
+                        "en-US");
+      cupsdSendIPPTrailer();
+    }
+
     if (execl(line, scheme, "cat", name, (char *)NULL))
     {
      /*
@@ -308,6 +361,20 @@ cat_ppd(const char *name)          /* I - PPD name */
       */
 
       fprintf(stderr, "ERROR: [cups-driverd] Bad PPD name \"%s\"!\n", name);
+
+      if (request_id)
+      {
+       snprintf(message, sizeof(message), "Bad PPD name \"%s\"!", name);
+
+       cupsdSendIPPHeader(IPP_OK, request_id);
+       cupsdSendIPPGroup(IPP_TAG_OPERATION);
+       cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+       cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language",
+                          "en-US");
+        cupsdSendIPPString(IPP_TAG_TEXT, "status-message", message);
+       cupsdSendIPPTrailer();
+      }
+
       return (1);
     }
 
@@ -315,17 +382,85 @@ cat_ppd(const char *name)         /* I - PPD name */
     * Try opening the file...
     */
 
-    if ((datadir = getenv("CUPS_DATADIR")) == NULL)
-      datadir = CUPS_DATADIR;
+#ifdef __APPLE__
+    if (!strncmp(name, "System/Library/Printers/PPDs/Contents/Resources/", 48) ||
+        !strncmp(name, "Library/Printers/PPDs/Contents/Resources/", 41))
+    {
+     /*
+      * Map ppd-name to Mac OS X standard locations...
+      */
+
+      snprintf(line, sizeof(line), "/%s", name);
+    }
+    else
+
+#elif defined(__linux)
+    if (!strncmp(name, "lsb/usr/", 8))
+    {
+     /*
+      * Map ppd-name to LSB standard /usr/share/ppd location...
+      */
+
+      snprintf(line, sizeof(line), "/usr/share/ppd/%s", name + 8);
+    }
+    else if (!strncmp(name, "lsb/opt/", 8))
+    {
+     /*
+      * Map ppd-name to LSB standard /opt/share/ppd location...
+      */
+
+      snprintf(line, sizeof(line), "/opt/share/ppd/%s", name + 8);
+    }
+    else if (!strncmp(name, "lsb/local/", 10))
+    {
+     /*
+      * Map ppd-name to LSB standard /usr/local/share/ppd location...
+      */
+
+      snprintf(line, sizeof(line), "/usr/local/share/ppd/%s", name + 10);
+    }
+    else
+
+#endif /* __APPLE__ */
+    {
+      if ((datadir = getenv("CUPS_DATADIR")) == NULL)
+       datadir = CUPS_DATADIR;
+
+      snprintf(line, sizeof(line), "%s/model/%s", datadir, name);
+    }
 
-    snprintf(line, sizeof(line), "%s/model/%s", datadir, name);
     if ((fp = cupsFileOpen(line, "r")) == NULL)
     {
       fprintf(stderr, "ERROR: [cups-driverd] Unable to open \"%s\" - %s\n",
               line, strerror(errno));
+
+      if (request_id)
+      {
+       snprintf(message, sizeof(message), "Unable to open \"%s\" - %s",
+                line, strerror(errno));
+
+       cupsdSendIPPHeader(IPP_NOT_FOUND, request_id);
+       cupsdSendIPPGroup(IPP_TAG_OPERATION);
+       cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+       cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language",
+                          "en-US");
+        cupsdSendIPPString(IPP_TAG_TEXT, "status-message", message);
+       cupsdSendIPPTrailer();
+      }
+
       return (1);
     }
 
+    if (request_id)
+    {
+      cupsdSendIPPHeader(IPP_OK, request_id);
+      cupsdSendIPPGroup(IPP_TAG_OPERATION);
+      cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+      cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language",
+                         "en-US");
+      cupsdSendIPPTrailer();
+    }
+
    /*
     * Now copy the file to stdout...
     */
@@ -377,8 +512,27 @@ compare_ppds(const ppd_info_t *p0, /* I - First PPD file */
                                      p1->record.make_and_model)) != 0)
     return (diff);
   else
-    return (strcasecmp(p0->record.natural_language,
-                       p1->record.natural_language));
+    return (strcasecmp(p0->record.languages[0],
+                       p1->record.languages[0]));
+}
+
+
+/*
+ * 'free_array()' - Free an array of strings.
+ */
+
+static void
+free_array(cups_array_t *a)            /* I - Array to free */
+{
+  char *ptr;                           /* Pointer to string */
+
+
+  for (ptr = (char *)cupsArrayFirst(a);
+       ptr;
+       ptr = (char *)cupsArrayNext(a))
+    free(ptr);
+
+  cupsArrayDelete(a);
 }
 
 
@@ -391,7 +545,7 @@ list_ppds(int        request_id,    /* I - Request ID */
           int        limit,            /* I - Limit */
          const char *opt)              /* I - Option argument */
 {
-  int          i;                      /* Looping var */
+  int          i, j;                   /* Looping vars */
   int          count;                  /* Number of PPDs to send */
   ppd_info_t   *ppd;                   /* Current PPD file */
   cups_file_t  *fp;                    /* ppds.dat file */
@@ -403,17 +557,27 @@ list_ppds(int        request_id,  /* I - Request ID */
   int          num_options;            /* Number of options */
   cups_option_t        *options;               /* Options */
   const char   *requested,             /* requested-attributes option */
-               *make;                  /* ppd-make option */
-  int          send_natural_language,  /* Send ppd-natural-language attribute? */
-               send_make,              /* Send ppd-make attribute? */
-               send_make_and_model,    /* Send ppd-make-and-model attribute? */
-               send_name,              /* Send ppd-name attribute? */
-               send_device_id,         /* Send ppd-device-id attribute? */
-               send_product;           /* Send ppd-product attribute? */
-
-
-  fprintf(stderr, "DEBUG2: [cups-driverd] list_ppds(request_id=%d, limit=%d, opt=\"%s\"\n",
-          request_id, limit, opt);
+               *device_id,             /* ppd-device-id option */
+               *language,              /* ppd-natural-language option */
+               *make,                  /* ppd-make option */
+               *make_and_model,        /* ppd-make-and-model option */
+               *product,               /* ppd-product option */
+               *psversion;             /* ppd-psversion option */
+  int          mam_len,                /* Length of ppd-make-and-model */
+               device_id_len,          /* Length of ppd-device-id */
+               send_natural_language,  /* Send ppd-natural-language? */
+               send_make,              /* Send ppd-make? */
+               send_make_and_model,    /* Send ppd-make-and-model? */
+               send_name,              /* Send ppd-name? */
+               send_device_id,         /* Send ppd-device-id? */
+               send_product,           /* Send ppd-product? */
+               send_psversion,         /* Send ppd-psversion? */
+               sent_header;            /* Sent the IPP header? */
+
+
+  fprintf(stderr,
+          "DEBUG2: [cups-driverd] list_ppds(request_id=%d, limit=%d, "
+          "opt=\"%s\"\n", request_id, limit, opt);
 
  /*
   * See if we a PPD database file...
@@ -428,45 +592,48 @@ list_ppds(int        request_id,  /* I - Request ID */
     cups_cachedir = CUPS_CACHEDIR;
 
   snprintf(filename, sizeof(filename), "%s/ppds.dat", cups_cachedir);
-  if (!stat(filename, &fileinfo) &&
-      (fileinfo.st_size % sizeof(ppd_rec_t)) == 0 &&
-      (NumPPDs = fileinfo.st_size / sizeof(ppd_rec_t)) > 0)
+  if ((fp = cupsFileOpen(filename, "r")) != NULL)
   {
    /*
-    * We have a ppds.dat file, so read it!
+    * See if we have the right sync word...
     */
 
-    AllocPPDs = NumPPDs;
+    unsigned ppdsync;                  /* Sync word */
 
-    if ((PPDs = malloc(sizeof(ppd_info_t) * NumPPDs)) == NULL)
+    if (cupsFileRead(fp, (char *)&ppdsync, sizeof(ppdsync))
+            == sizeof(ppdsync) &&
+        ppdsync == PPD_SYNC &&
+        !stat(filename, &fileinfo) &&
+       ((fileinfo.st_size - sizeof(ppdsync)) % sizeof(ppd_rec_t)) == 0 &&
+       (NumPPDs = (fileinfo.st_size - sizeof(ppdsync)) /
+                  sizeof(ppd_rec_t)) > 0)
     {
-      fprintf(stderr,
-              "ERROR: [cups-driverd] Unable to allocate memory for %d "
-             "PPD files!\n", NumPPDs);
-      NumPPDs   = 0;
-      AllocPPDs = 0;
-    }
-    else if ((fp = cupsFileOpen(filename, "r")) != NULL)
-    {
-      for (i = NumPPDs, ppd = PPDs; i > 0; i --, ppd ++)
+     /*
+      * We have a ppds.dat file, so read it!
+      */
+
+      if ((PPDs = malloc(sizeof(ppd_info_t) * NumPPDs)) == NULL)
+       fprintf(stderr,
+               "ERROR: [cups-driverd] Unable to allocate memory for %d "
+               "PPD files!\n", NumPPDs);
+      else
       {
-        cupsFileRead(fp, (char *)&(ppd->record), sizeof(ppd_rec_t));
-       ppd->found = 0;
-      }
+        AllocPPDs = NumPPDs;
 
-      cupsFileClose(fp);
+       for (i = NumPPDs, ppd = PPDs; i > 0; i --, ppd ++)
+       {
+         cupsFileRead(fp, (char *)&(ppd->record), sizeof(ppd_rec_t));
+         ppd->found = 0;
+       }
 
-      fprintf(stderr, "INFO: [cups-driverd] Read \"%s\", %d PPDs...\n",
-              filename, NumPPDs);
-    }
-    else
-    {
-      fprintf(stderr, "ERROR: [cups-driverd] Unable to read \"%s\" - %s\n", filename,
-              strerror(errno));
-      NumPPDs = 0;
+       fprintf(stderr, "INFO: [cups-driverd] Read \"%s\", %d PPDs...\n",
+               filename, NumPPDs);
+      }
     }
-  }
 
+    cupsFileClose(fp);
+  }
+  
  /*
   * Load all PPDs in the specified directory and below...
   */
@@ -477,7 +644,31 @@ list_ppds(int        request_id,   /* I - Request ID */
     cups_datadir = CUPS_DATADIR;
 
   snprintf(model, sizeof(model), "%s/model", cups_datadir);
-  load_ppds(model, "");
+  load_ppds(model, "", 1);
+
+#ifdef __APPLE__
+ /*
+  * Load PPDs from standard Mac OS X locations...
+  */
+
+  load_ppds("/Library/Printers/PPDs/Contents/Resources",
+            "Library/Printers/PPDs/Contents/Resources", 0);
+  load_ppds("/Library/Printers/PPDs/Contents/Resources/en.lproj",
+            "Library/Printers/PPDs/Contents/Resources/en.lproj", 0);
+  load_ppds("/System/Library/Printers/PPDs/Contents/Resources",
+            "System/Library/Printers/PPDs/Contents/Resources", 0);
+  load_ppds("/System/Library/Printers/PPDs/Contents/Resources/en.lproj",
+            "System/Library/Printers/PPDs/Contents/Resources/en.lproj", 0);
+
+#elif defined(__linux)
+ /*
+  * Load PPDs from LSB-defined locations...
+  */
+
+  load_ppds("/usr/local/share/ppds", "lsb/local", 1);
+  load_ppds("/usr/share/ppds", "lsb/usr", 1);
+  load_ppds("/opt/share/ppds", "lsb/opt", 1);
+#endif /* __APPLE__ */
 
  /*
   * Cull PPD files that are no longer present...
@@ -513,6 +704,11 @@ list_ppds(int        request_id,   /* I - Request ID */
   {
     if ((fp = cupsFileOpen(filename, "w")) != NULL)
     {
+      unsigned ppdsync = PPD_SYNC;     /* Sync word */
+
+
+      cupsFileWrite(fp, (char *)&ppdsync, sizeof(ppdsync));
+
       for (i = NumPPDs, ppd = PPDs; i > 0; i --, ppd ++)
        cupsFileWrite(fp, (char *)&(ppd->record), sizeof(ppd_rec_t));
 
@@ -538,7 +734,7 @@ list_ppds(int        request_id,    /* I - Request ID */
   * Add the raw driver...
   */
 
-  add_ppd("raw", "en", "Raw", "Raw Queue", "", "", 0, 0);
+  add_ppd("raw", "en", "Raw", "Raw Queue", "", "", "", 0, 0);
 
  /*
   * Sort the PPDs by make and model...
@@ -552,12 +748,46 @@ list_ppds(int        request_id,  /* I - Request ID */
   * Send IPP attributes...
   */
 
-  num_options = cupsParseOptions(opt, 0, &options);
-  requested   = cupsGetOption("requested-attributes", num_options, options);
-  make        = cupsGetOption("ppd-make", num_options, options);
+  num_options    = cupsParseOptions(opt, 0, &options);
+  requested      = cupsGetOption("requested-attributes", num_options, options);
+  device_id      = cupsGetOption("ppd-device-id", num_options, options);
+  language       = cupsGetOption("ppd-natural-language", num_options, options);
+  make           = cupsGetOption("ppd-make", num_options, options);
+  make_and_model = cupsGetOption("ppd-make-and-model", num_options, options);
+  product        = cupsGetOption("ppd-product", num_options, options);
+  psversion      = cupsGetOption("ppd-psversion", num_options, options);
+
+  if (make_and_model)
+    mam_len = strlen(make_and_model);
+  else
+    mam_len = 0;
 
-  fprintf(stderr, "DEBUG: [cups-driverd] requested=\"%s\"\n",
-          requested ? requested : "(nil)");
+  if (device_id)
+    device_id_len = strlen(device_id);
+  else
+    device_id_len = 0;
+
+  if (requested)
+    fprintf(stderr, "DEBUG: [cups-driverd] requested-attributes=\"%s\"\n",
+           requested);
+  if (device_id)
+    fprintf(stderr, "DEBUG: [cups-driverd] ppd-device-id=\"%s\"\n",
+           device_id);
+  if (language)
+    fprintf(stderr, "DEBUG: [cups-driverd] ppd-natural-language=\"%s\"\n",
+           language);
+  if (make)
+    fprintf(stderr, "DEBUG: [cups-driverd] ppd-make=\"%s\"\n",
+           make);
+  if (make_and_model)
+    fprintf(stderr, "DEBUG: [cups-driverd] ppd-make-and-model=\"%s\"\n",
+           make_and_model);
+  if (product)
+    fprintf(stderr, "DEBUG: [cups-driverd] ppd-product=\"%s\"\n",
+           product);
+  if (psversion)
+    fprintf(stderr, "DEBUG: [cups-driverd] ppd-psversion=\"%s\"\n",
+           psversion);
 
   if (!requested || strstr(requested, "all"))
   {
@@ -567,6 +797,7 @@ list_ppds(int        request_id,    /* I - Request ID */
     send_natural_language = 1;
     send_device_id        = 1;
     send_product          = 1;
+    send_psversion        = 1;
   }
   else
   {
@@ -578,14 +809,12 @@ list_ppds(int        request_id,  /* I - Request ID */
     send_natural_language = strstr(requested, "ppd-natural-language") != NULL;
     send_device_id        = strstr(requested, "ppd-device-id") != NULL;
     send_product          = strstr(requested, "ppd-product") != NULL;
+    send_psversion        = strstr(requested, "ppd-psversion") != NULL;
   }
 
   puts("Content-Type: application/ipp\n");
 
-  cupsdSendIPPHeader(IPP_OK, request_id);
-  cupsdSendIPPGroup(IPP_TAG_OPERATION);
-  cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
-  cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", "en-US");
+  sent_header = 0;
 
   if (limit <= 0 || limit > NumPPDs)
     count = NumPPDs;
@@ -593,59 +822,143 @@ list_ppds(int        request_id, /* I - Request ID */
     count = limit;
 
   for (i = NumPPDs, ppd = PPDs; count > 0 && i > 0; i --, ppd ++)
-    if (!make || !strcasecmp(ppd->record.make, make))
+  {
+   /*
+    * Filter PPDs based on make, model, or device ID...
+    */
+
+    if (device_id && strncasecmp(ppd->record.device_id, device_id,
+                                 device_id_len))
+      continue;                                /* TODO: implement smart compare */
+
+    if (language)
     {
-     /*
-      * Send this PPD...
-      */
+      for (j = 0; j < PPD_MAX_LANG; j ++)
+       if (!ppd->record.languages[j][0] ||
+           !strcasecmp(ppd->record.languages[j], language))
+         break;
+
+      if (j >= PPD_MAX_LANG || !ppd->record.languages[j][0])
+       continue;
+    }
+
+    if (make && strcasecmp(ppd->record.make, make))
+      continue;
+
+    if (make_and_model && strncasecmp(ppd->record.make_and_model,
+                                      make_and_model, mam_len))
+      continue;
+
+    if (product)
+    {
+      for (j = 0; j < PPD_MAX_PROD; j ++)
+       if (!ppd->record.products[j][0] ||
+           !strcasecmp(ppd->record.products[j], product))
+         break;
 
-      fprintf(stderr, "DEBUG: [cups-driverd] Sending %s (%s)...\n",
-              ppd->record.name, ppd->record.make_and_model);
+      if (j >= PPD_MAX_PROD || !ppd->record.products[j][0])
+       continue;
+    }
 
-      count --;
+    if (psversion)
+    {
+      for (j = 0; j < PPD_MAX_VERS; j ++)
+       if (!ppd->record.psversions[j][0] ||
+           !strcasecmp(ppd->record.psversions[j], psversion))
+         break;
 
-      cupsdSendIPPGroup(IPP_TAG_PRINTER);
+      if (j >= PPD_MAX_VERS || !ppd->record.psversions[j][0])
+       continue;
+    }
 
-      if (send_name)
-        cupsdSendIPPString(IPP_TAG_NAME, "ppd-name", ppd->record.name);
+   /*
+    * Send this PPD...
+    */
 
-      if (send_natural_language)
-        cupsdSendIPPString(IPP_TAG_LANGUAGE, "ppd-natural-language",
-                          ppd->record.natural_language);
+    if (!sent_header)
+    {
+      sent_header = 1;
 
-      if (send_make)
-        cupsdSendIPPString(IPP_TAG_TEXT, "ppd-make", ppd->record.make);
+      cupsdSendIPPHeader(IPP_OK, request_id);
+      cupsdSendIPPGroup(IPP_TAG_OPERATION);
+      cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+      cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", "en-US");
+    }
 
-      if (send_make_and_model)
-        cupsdSendIPPString(IPP_TAG_TEXT, "ppd-make-and-model",
-                          ppd->record.make_and_model);
+    fprintf(stderr, "DEBUG: [cups-driverd] Sending %s (%s)...\n",
+           ppd->record.name, ppd->record.make_and_model);
 
-      if (send_device_id)
-        cupsdSendIPPString(IPP_TAG_TEXT, "ppd-device-id",
-                          ppd->record.device_id);
+    count --;
 
-      if (send_product)
-        cupsdSendIPPString(IPP_TAG_TEXT, "ppd-product",
-                          ppd->record.product);
+    cupsdSendIPPGroup(IPP_TAG_PRINTER);
 
-     /*
-      * If we have only requested the ppd-make attribute, then skip
-      * the remaining PPDs with this make...
-      */
+    if (send_name)
+      cupsdSendIPPString(IPP_TAG_NAME, "ppd-name", ppd->record.name);
 
-      if (requested && !strcmp(requested, "ppd-make"))
-      {
-        const char     *this_make;     /* This ppd-make */
+    if (send_natural_language)
+    {
+      cupsdSendIPPString(IPP_TAG_LANGUAGE, "ppd-natural-language",
+                        ppd->record.languages[0]);
 
+      for (j = 1; j < PPD_MAX_LANG && ppd->record.languages[j][0]; j ++)
+       cupsdSendIPPString(IPP_TAG_LANGUAGE, "", ppd->record.languages[j]);
+    }
 
-        for (this_make = ppd->record.make, i --, ppd ++; i > 0; i --, ppd ++)
-         if (strcasecmp(this_make, ppd->record.make))
-           break;
+    if (send_make)
+      cupsdSendIPPString(IPP_TAG_TEXT, "ppd-make", ppd->record.make);
 
-        i ++;
-       ppd --;
-      }
+    if (send_make_and_model)
+      cupsdSendIPPString(IPP_TAG_TEXT, "ppd-make-and-model",
+                        ppd->record.make_and_model);
+
+    if (send_device_id)
+      cupsdSendIPPString(IPP_TAG_TEXT, "ppd-device-id",
+                        ppd->record.device_id);
+
+    if (send_product)
+    {
+      cupsdSendIPPString(IPP_TAG_TEXT, "ppd-product",
+                        ppd->record.products[0]);
+
+      for (j = 1; j < PPD_MAX_PROD && ppd->record.products[j][0]; j ++)
+       cupsdSendIPPString(IPP_TAG_TEXT, "", ppd->record.products[j]);
+    }
+
+    if (send_psversion)
+    {
+      cupsdSendIPPString(IPP_TAG_TEXT, "ppd-psversion",
+                        ppd->record.psversions[0]);
+
+      for (j = 1; j < PPD_MAX_VERS && ppd->record.psversions[j][0]; j ++)
+       cupsdSendIPPString(IPP_TAG_TEXT, "", ppd->record.psversions[j]);
+    }
+
+   /*
+    * If we have only requested the ppd-make attribute, then skip
+    * the remaining PPDs with this make...
+    */
+
+    if (requested && !strcmp(requested, "ppd-make"))
+    {
+      const char       *this_make;     /* This ppd-make */
+
+
+      for (this_make = ppd->record.make, i --, ppd ++; i > 0; i --, ppd ++)
+       if (strcasecmp(this_make, ppd->record.make))
+         break;
+
+      i ++;
+      ppd --;
     }
+  }
+
+  if (!sent_header)
+  {
+    cupsdSendIPPHeader(IPP_NOT_FOUND, request_id);
+    cupsdSendIPPGroup(IPP_TAG_OPERATION);
+    cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8");
+    cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", "en-US");
+  }
 
   cupsdSendIPPTrailer();
 
@@ -659,7 +972,8 @@ list_ppds(int        request_id,    /* I - Request ID */
 
 static int                             /* O - 1 on success, 0 on failure */
 load_ppds(const char *d,               /* I - Actual directory */
-          const char *p)               /* I - Virtual path in name */
+          const char *p,               /* I - Virtual path in name */
+         int        descend)           /* I - Descend into directories? */
 {
   int          i;                      /* Looping var */
   cups_file_t  *fp;                    /* Pointer to file */
@@ -677,8 +991,11 @@ load_ppds(const char *d,           /* I - Actual directory */
                model_name[256],        /* ModelName */
                nick_name[256],         /* NickName */
                device_id[256],         /* 1284DeviceID */
-               product[256];           /* Product */
-  cups_array_t *products;              /* Array of product strings */
+               product[256],           /* Product */
+               psversion[256];         /* PSVersion */
+  cups_array_t *products,              /* Product array */
+               *psversions,            /* PSVersion array */
+               *cups_languages;        /* cupsLanguages array */
   ppd_info_t   *ppd,                   /* New PPD file */
                key;                    /* Search key */
   int          new_ppd;                /* Is this a new PPD? */
@@ -688,7 +1005,7 @@ load_ppds(const char *d,           /* I - Actual directory */
                *language;              /* Language code */
   }            languages[] =
   {
-    { "chinese",       "cn" },
+    { "chinese",       "zh" },
     { "danish",                "da" },
     { "dutch",         "nl" },
     { "english",       "en" },
@@ -711,7 +1028,8 @@ load_ppds(const char *d,           /* I - Actual directory */
 
   if ((dir = cupsDirOpen(d)) == NULL)
   {
-    fprintf(stderr, "ERROR: [cups-driverd] Unable to open PPD directory \"%s\": %s\n",
+    fprintf(stderr,
+            "ERROR: [cups-driverd] Unable to open PPD directory \"%s\": %s\n",
             d, strerror(errno));
     return (0);
   }
@@ -742,11 +1060,12 @@ load_ppds(const char *d,         /* I - Actual directory */
       * Do subdirectory...
       */
 
-      if (!load_ppds(filename, name))
-      {
-        cupsDirClose(dir);
-        return (1);
-      }
+      if (descend)
+       if (!load_ppds(filename, name, 1))
+       {
+         cupsDirClose(dir);
+         return (1);
+       }
 
       continue;
     }
@@ -802,7 +1121,9 @@ load_ppds(const char *d,           /* I - Actual directory */
     * Now read until we get the NickName field...
     */
 
-    products = cupsArrayNew(NULL, NULL);
+    cups_languages = cupsArrayNew(NULL, NULL);
+    products       = cupsArrayNew(NULL, NULL);
+    psversions     = cupsArrayNew(NULL, NULL);
 
     model_name[0]    = '\0';
     nick_name[0]     = '\0';
@@ -830,6 +1151,39 @@ load_ppds(const char *d,          /* I - Actual directory */
        sscanf(line, "%*[^\"]\"(%255[^)]", product);
        cupsArrayAdd(products, strdup(product));
       }
+      else if (!strncasecmp(line, "*PSVersion:", 11))
+      {
+       sscanf(line, "%*[^\"]\"%255[^\"]", psversion);
+       cupsArrayAdd(psversions, strdup(psversion));
+      }
+      else if (!strncasecmp(line, "*cupsLanguages:", 15))
+      {
+        char   *start;                 /* Start of language */
+
+
+        for (start = line + 15; *start && isspace(*start & 255); start ++);
+
+       if (*start++ == '\"')
+       {
+         while (*start)
+         {
+           for (ptr = start + 1;
+                *ptr && *ptr != '\"' && !isspace(*ptr & 255);
+                ptr ++);
+
+            if (*ptr)
+           {
+             *ptr++ = '\0';
+
+             while (isspace(*ptr & 255))
+               *ptr++ = '\0';
+            }
+
+            cupsArrayAdd(cups_languages, strdup(start));
+           start = ptr;
+         }
+       }
+      }
       else if (!strncmp(line, "*OpenUI", 7))
       {
        /*
@@ -837,7 +1191,8 @@ load_ppds(const char *d,           /* I - Actual directory */
        * before the first OpenUI...
        */
 
-        if ((model_name[0] || nick_name[0]) && cupsArrayCount(products) > 0)
+        if ((model_name[0] || nick_name[0]) && cupsArrayCount(products) > 0 &&
+           cupsArrayCount(psversions) > 0)
          break;
       }
     }
@@ -861,7 +1216,8 @@ load_ppds(const char *d,           /* I - Actual directory */
     while (isspace(make_model[0] & 255))
       _cups_strcpy(make_model, make_model + 1);
 
-    if (!make_model[0] || cupsArrayCount(products) == 0)
+    if (!make_model[0] || cupsArrayCount(products) == 0 ||
+        cupsArrayCount(psversions) == 0)
     {
      /*
       * We don't have all the info needed, so skip this file...
@@ -874,12 +1230,12 @@ load_ppds(const char *d,         /* I - Actual directory */
       if (cupsArrayCount(products) == 0)
         fprintf(stderr, "WARNING: Missing Product in %s!\n", filename);
 
-      for (ptr = (char *)cupsArrayFirst(products);
-           ptr;
-          ptr = (char *)cupsArrayNext(products))
-       free(ptr);
+      if (cupsArrayCount(psversions) == 0)
+        fprintf(stderr, "WARNING: Missing PSVersion in %s!\n", filename);
 
-      cupsArrayDelete(products);
+      free_array(products);
+      free_array(psversions);
+      free_array(cups_languages);
 
       continue;
     }
@@ -1007,10 +1363,12 @@ load_ppds(const char *d,                /* I - Actual directory */
 
       fprintf(stderr, "DEBUG: [cups-driverd] Adding ppd \"%s\"...\n", name);
 
-      /* TODO: Support multiple Products... */
-      if (!add_ppd(name, lang_version, manufacturer, make_model, device_id,
-                   (char *)cupsArrayFirst(products),
-                   dent->fileinfo.st_mtime, dent->fileinfo.st_size))
+      ppd = add_ppd(name, lang_version, manufacturer, make_model, device_id,
+                    (char *)cupsArrayFirst(products),
+                    (char *)cupsArrayFirst(psversions),
+                    dent->fileinfo.st_mtime, dent->fileinfo.st_size);
+
+      if (!ppd)
       {
         cupsDirClose(dir);
        return (0);
@@ -1034,23 +1392,44 @@ load_ppds(const char *d,                /* I - Actual directory */
       strlcpy(ppd->record.make, manufacturer, sizeof(ppd->record.make));
       strlcpy(ppd->record.make_and_model, make_model,
               sizeof(ppd->record.make_and_model));
-      strlcpy(ppd->record.natural_language, lang_version,
-              sizeof(ppd->record.natural_language));
-      strlcpy(ppd->record.product, (char *)cupsArrayFirst(products),
-              sizeof(ppd->record.product));
+      strlcpy(ppd->record.languages[0], lang_version,
+              sizeof(ppd->record.languages[0]));
+      strlcpy(ppd->record.products[0], (char *)cupsArrayFirst(products),
+              sizeof(ppd->record.products[0]));
+      strlcpy(ppd->record.psversions[0], (char *)cupsArrayFirst(psversions),
+              sizeof(ppd->record.psversions[0]));
       strlcpy(ppd->record.device_id, device_id, sizeof(ppd->record.device_id));
     }
 
    /*
-    * Free products...
+    * Add remaining products, versions, and languages...
     */
 
-    for (ptr = (char *)cupsArrayFirst(products);
-         ptr;
-        ptr = (char *)cupsArrayNext(products))
-      free(ptr);
+    for (i = 1;
+         i < PPD_MAX_PROD && (ptr = (char *)cupsArrayNext(products)) != NULL;
+        i ++)
+      strlcpy(ppd->record.products[i], ptr,
+              sizeof(ppd->record.products[0]));
+
+    for (i = 1;
+         i < PPD_MAX_VERS && (ptr = (char *)cupsArrayNext(psversions)) != NULL;
+        i ++)
+      strlcpy(ppd->record.psversions[i], ptr,
+              sizeof(ppd->record.psversions[0]));
 
-    cupsArrayDelete(products);
+    for (i = 1, ptr = (char *)cupsArrayFirst(cups_languages);
+         i < PPD_MAX_LANG && ptr;
+        i ++, ptr = (char *)cupsArrayNext(cups_languages))
+      strlcpy(ppd->record.languages[i], ptr,
+              sizeof(ppd->record.languages[0]));
+
+   /*
+    * Free products, versions, and languages...
+    */
+
+    free_array(cups_languages);
+    free_array(products);
+    free_array(psversions);
 
     ChangedPPD = 1;
   }
@@ -1068,7 +1447,10 @@ load_ppds(const char *d,         /* I - Actual directory */
 static int                             /* O - 1 on success, 0 on failure */
 load_drivers(void)
 {
-  const char   *server_bin;            /* CUPS_SERVERBIN environment variable */
+  int          i;                      /* Looping var */
+  char         *start,                 /* Start of value */
+               *ptr;                   /* Pointer into string */
+  const char   *server_bin;            /* CUPS_SERVERBIN env variable */
   char         drivers[1024];          /* Location of driver programs */
   FILE         *fp;                    /* Pipe to driver program */
   cups_dir_t   *dir;                   /* Directory pointer */
@@ -1076,11 +1458,13 @@ load_drivers(void)
   char         filename[1024],         /* Name of driver */
                line[2048],             /* Line from driver */
                name[512],              /* ppd-name */
-               natural_language[128],  /* ppd-natural-language */
                make[128],              /* ppd-make */
-               make_and_model[256],    /* ppd-make-and-model */
-               device_id[256],         /* ppd-device-id */
-               product[256];           /* ppd-product */
+               make_and_model[128],    /* ppd-make-and-model */
+               device_id[128],         /* ppd-device-id */
+               languages[128],         /* ppd-natural-language */
+               product[128],           /* ppd-product */
+               psversion[128];         /* ppd-psversion */
+  ppd_info_t   *ppd;                   /* Newly added PPD */
 
 
  /*
@@ -1126,17 +1510,18 @@ load_drivers(void)
         * Each line is of the form:
        *
        *   "ppd-name" ppd-natural-language "ppd-make" "ppd-make-and-model" \
-       *       "ppd-device-id" "ppd-product"
+       *       "ppd-device-id" "ppd-product" "ppd-psversion"
        */
 
         device_id[0] = '\0';
        product[0]   = '\0';
+       psversion[0] = '\0';
 
         if (sscanf(line, "\"%511[^\"]\"%127s%*[ \t]\"%127[^\"]\""
-                        "%*[ \t]\"%256[^\"]\"%*[ \t]\"%256[^\"]\""
-                        "%*[ \t]\"%256[^\"]\"",
-                  name, natural_language, make, make_and_model,
-                  device_id, product) < 4)
+                        "%*[ \t]\"%127[^\"]\"%*[ \t]\"%127[^\"]\""
+                        "%*[ \t]\"%127[^\"]\"%*[ \t]\"%127[^\"]\"",
+                  name, languages, make, make_and_model,
+                  device_id, product, psversion) < 4)
         {
         /*
          * Bad format; strip trailing newline and write an error message.
@@ -1155,13 +1540,34 @@ load_drivers(void)
          * Add the device to the array of available devices...
          */
 
-          if (!add_ppd(name, natural_language, make, make_and_model, device_id,
-                      product, 0, 0))
+          if ((start = strchr(languages, ',')) != NULL)
+           *start++ = '\0';
+
+          ppd = add_ppd(name, languages, make, make_and_model, device_id,
+                       product, psversion, 0, 0);
+
+          if (!ppd)
          {
             cupsDirClose(dir);
            return (0);
          }
 
+          if (start && *start)
+         {
+           for (i = 1; i < PPD_MAX_LANG && *start; i ++)
+           {
+             if ((ptr = strchr(start, ',')) != NULL)
+               *ptr++ = '\0';
+             else
+               ptr = start + strlen(start);
+
+              strlcpy(ppd->record.languages[i], start,
+                     sizeof(ppd->record.languages[0]));
+
+             start = ptr;
+           }
+          }
+
           fprintf(stderr, "DEBUG: [cups-driverd] Added dynamic PPD \"%s\"...\n",
                  name);
        }
@@ -1181,5 +1587,5 @@ load_drivers(void)
 
 
 /*
- * End of "$Id: cups-driverd.c 6377 2007-03-21 07:17:11Z mike $".
+ * End of "$Id: cups-driverd.c 6508 2007-05-03 20:07:14Z mike $".
  */
index 2ae4b680593c6c2a3577689347e4f5d14b0ad193..373b7c535cab7caf3021e3bd52eb664113282053 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: dirsvc.c 6376 2007-03-21 06:39:10Z mike $"
+ * "$Id: dirsvc.c 6483 2007-04-30 17:16:16Z mike $"
  *
  *   Directory services routines for the Common UNIX Printing System (CUPS).
  *
@@ -2931,7 +2931,7 @@ send_cups_browse(cupsd_printer_t *p)      /* I - Printer to send */
        {
          httpAssembleURIf(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipp", NULL,
                           iface->hostname, iface->port,
-                          (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s%s" :
+                          (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s" :
                                                            "/printers/%s",
                           p->name);
          snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\" %s\n",
@@ -3802,5 +3802,5 @@ update_polling(void)
 
 
 /*
- * End of "$Id: dirsvc.c 6376 2007-03-21 06:39:10Z mike $".
+ * End of "$Id: dirsvc.c 6483 2007-04-30 17:16:16Z mike $".
  */
index 5a8555ac4e47ffac05c9c1ea77461c82f1c5e987..bbba0162121e0e672b348544e1d1e02d9b5ef775 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: ipp.c 6433 2007-04-02 21:50:50Z mike $"
+ * "$Id: ipp.c 6508 2007-05-03 20:07:14Z mike $"
  *
  *   IPP routines for the Common UNIX Printing System (CUPS) scheduler.
  *
@@ -65,6 +65,7 @@
  *   get_job_attrs()             - Get job attributes.
  *   get_jobs()                  - Get a list of jobs for the specified printer.
  *   get_notifications()         - Get events for a subscription.
+ *   get_ppd()                   - Get a named PPD from the local system.
  *   get_ppds()                  - Get the list of PPD files on the local
  *                                 system.
  *   get_printer_attrs()         - Get printer attributes.
@@ -92,6 +93,7 @@
  *   start_printer()             - Start a printer.
  *   stop_printer()              - Stop a printer.
  *   url_encode_attr()           - URL-encode a string attribute.
+ *   url_encode_string()         - URL-encode a string.
  *   user_allowed()              - See if a user is allowed to print to a queue.
  *   validate_job()              - Validate printer options and destination.
  *   validate_name()             - Make sure the printer name only contains
@@ -178,6 +180,7 @@ static void get_devices(cupsd_client_t *con);
 static void    get_jobs(cupsd_client_t *con, ipp_attribute_t *uri);
 static void    get_job_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
 static void    get_notifications(cupsd_client_t *con);
+static void    get_ppd(cupsd_client_t *con, ipp_attribute_t *uri);
 static void    get_ppds(cupsd_client_t *con);
 static void    get_printers(cupsd_client_t *con, int type);
 static void    get_printer_attrs(cupsd_client_t *con, ipp_attribute_t *uri);
@@ -216,6 +219,7 @@ static void start_printer(cupsd_client_t *con, ipp_attribute_t *uri);
 static void    stop_printer(cupsd_client_t *con, ipp_attribute_t *uri);
 static void    url_encode_attr(ipp_attribute_t *attr, char *buffer,
                                int bufsize);
+static char    *url_encode_string(const char *s, char *buffer, int bufsize);
 static int     user_allowed(cupsd_printer_t *p, const char *username);
 static void    validate_job(cupsd_client_t *con, ipp_attribute_t *uri);
 static int     validate_name(const char *name);
@@ -344,6 +348,8 @@ cupsdProcessIPPRequest(
       else if ((attr = ippFindAttribute(con->request, "job-uri",
                                         IPP_TAG_URI)) != NULL)
        uri = attr;
+      else if (con->request->request.op.operation_id == CUPS_GET_PPD)
+        uri = ippFindAttribute(con->request, "ppd-name", IPP_TAG_NAME);
       else
        uri = NULL;
 
@@ -399,11 +405,12 @@ cupsdProcessIPPRequest(
         if (!uri)
        {
          cupsdLogMessage(CUPSD_LOG_ERROR,
-                         "Missing printer-uri or job-uri attribute!");
+                         "Missing printer-uri, job-uri, or ppd-name "
+                         "attribute!");
 
          cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL,
-                       "%04X %s Missing printer-uri or job-uri attribute",
-                       IPP_BAD_REQUEST, con->http.hostname);
+                       "%04X %s Missing printer-uri, job-uri, or ppd-name "
+                       "attribute", IPP_BAD_REQUEST, con->http.hostname);
         }
 
        cupsdLogMessage(CUPSD_LOG_DEBUG, "Request attributes follow...");
@@ -572,6 +579,10 @@ cupsdProcessIPPRequest(
               get_devices(con);
               break;
 
+         case CUPS_GET_PPD :
+              get_ppd(con, uri);
+              break;
+
          case CUPS_GET_PPDS :
               get_ppds(con);
               break;
@@ -665,6 +676,15 @@ cupsdProcessIPPRequest(
 
        length = ippLength(con->response);
 
+       if (con->file >= 0 && !con->pipe_pid)
+       {
+         struct stat   fileinfo;       /* File information */
+
+
+          if (!fstat(con->file, &fileinfo))
+           length += fileinfo.st_size;
+       }
+
        if (httpPrintf(HTTP(con), "Content-Length: " CUPS_LLFMT "\r\n\r\n",
                       CUPS_LLCAST length) < 0)
          return (0);
@@ -674,6 +694,11 @@ cupsdProcessIPPRequest(
 
        con->http.data_encoding  = HTTP_ENCODE_LENGTH;
        con->http.data_remaining = length;
+
+       if (con->http.data_remaining <= INT_MAX)
+         con->http._data_remaining = con->http.data_remaining;
+       else
+         con->http._data_remaining = INT_MAX;
       }
 
       cupsdAddSelect(con->http.fd, (cupsd_selfunc_t)cupsdReadClient,
@@ -5887,6 +5912,147 @@ get_notifications(cupsd_client_t *con)  /* I - Client connection */
 }
 
 
+/*
+ * 'get_ppd()' - Get a named PPD from the local system.
+ */
+
+static void
+get_ppd(cupsd_client_t  *con,          /* I - Client connection */
+        ipp_attribute_t *uri)          /* I - Printer URI or PPD name */
+{
+  http_status_t                status;         /* Policy status */
+  cupsd_printer_t      *dest;          /* Destination */
+  cups_ptype_t         dtype;          /* Destination type */
+
+
+  cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppd(%p[%d], %p[%s=%s])", con,
+                  con->http.fd, uri, uri->name, uri->values[0].string.text);
+
+  if (!strcmp(uri->name, "ppd-name"))
+  {
+   /*
+    * Return a PPD file from cups-driverd...
+    */
+
+    char       command[1024],  /* cups-driverd command */
+               options[1024],  /* Options to pass to command */
+               ppd_name[1024]; /* ppd-name */
+
+
+   /*
+    * Check policy...
+    */
+
+    if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK)
+    {
+      send_http_error(con, status, NULL);
+      return;
+    }
+
+   /*
+    * Run cups-driverd command with the given options...
+    */
+
+    snprintf(command, sizeof(command), "%s/daemon/cups-driverd", ServerBin);
+    url_encode_string(uri->values[0].string.text, ppd_name, sizeof(ppd_name));
+    snprintf(options, sizeof(options), "get+%d+%s",
+             con->request->request.op.request_id, ppd_name);
+
+    if (cupsdSendCommand(con, command, options, 0))
+    {
+     /*
+      * Command started successfully, don't send an IPP response here...
+      */
+
+      ippDelete(con->response);
+      con->response = NULL;
+    }
+    else
+    {
+     /*
+      * Command failed, return "internal error" so the user knows something
+      * went wrong...
+      */
+
+      send_ipp_status(con, IPP_INTERNAL_ERROR,
+                     _("cups-driverd failed to execute."));
+    }
+  }
+  else if (!strcmp(uri->name, "printer-uri") &&
+           cupsdValidateDest(uri->values[0].string.text, &dtype, &dest))
+  {
+    int        i;                      /* Looping var */
+    char       filename[1024];         /* PPD filename */
+
+
+   /*
+    * Check policy...
+    */
+
+    if ((status = cupsdCheckPolicy(dest->op_policy_ptr, con, NULL)) != HTTP_OK)
+    {
+      send_http_error(con, status, NULL);
+      return;
+    }
+
+   /*
+    * See if we need the PPD for a class or remote printer...
+    */
+
+    if (dtype & CUPS_PRINTER_REMOTE)
+    {
+      send_ipp_status(con, CUPS_SEE_OTHER, NULL);
+      ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_URI,
+                   "printer-uri", NULL, dest->uri);
+      return;
+    }
+    else if (dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))
+    {
+      for (i = 0; i < dest->num_printers; i ++)
+        if (!(dest->printers[i]->type &
+             (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT |
+              CUPS_PRINTER_REMOTE)))
+         break;
+
+      if (i < dest->num_printers)
+        dest = dest->printers[i];
+      else
+      {
+       send_ipp_status(con, CUPS_SEE_OTHER, NULL);
+       ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_URI,
+                    "printer-uri", NULL, dest->printers[0]->uri);
+        return;
+      }
+    }
+
+   /*
+    * Found the printer with the PPD file, now see if there is one...
+    */
+
+    snprintf(filename, sizeof(filename), "%s/ppd/%s.ppd", ServerRoot,
+             dest->name);
+
+    if ((con->file = open(filename, O_RDONLY)) < 0)
+    {
+      send_ipp_status(con, IPP_NOT_FOUND,
+                      _("The PPD file \"%s\" could not be opened: %s"),
+                     uri->values[i].string.text, strerror(errno));
+      return;
+    }
+
+    fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC);
+
+    con->pipe_pid = 0;
+
+    send_ipp_status(con, IPP_OK, NULL);
+  }
+  else
+    send_ipp_status(con, IPP_NOT_FOUND,
+                    _("The PPD file \"%s\" could not be found."),
+                    uri->values[0].string.text);
+}
+
+
 /*
  * 'get_ppds()' - Get the list of PPD files on the local system.
  */
@@ -5896,13 +6062,26 @@ get_ppds(cupsd_client_t *con)           /* I - Client connection */
 {
   http_status_t                status;         /* Policy status */
   ipp_attribute_t      *limit,         /* Limit attribute */
+                       *device,        /* ppd-device-id attribute */
+                       *language,      /* ppd-natural-language attribute */
                        *make,          /* ppd-make attribute */
+                       *model,         /* ppd-make-and-model attribute */
+                       *product,       /* ppd-product attribute */
+                       *psversion,     /* ppd-psverion attribute */
                        *requested;     /* requested-attributes attribute */
-  char                 command[1024],  /* cups-deviced command */
+  char                 command[1024],  /* cups-driverd command */
                        options[1024],  /* Options to pass to command */
-                       requested_str[256],
+                       device_str[256],/* Escaped ppd-device-id string */
+                       language_str[256],
+                                       /* Escaped ppd-natural-language string */
+                       make_str[256],  /* Escaped ppd-make string */
+                       model_str[256], /* Escaped ppd-make-and-model string */
+                       product_str[256],
+                                       /* Escaped ppd-product string */
+                       psversion_str[256],
+                                       /* Escaped ppd-psversion string */
+                       requested_str[256];
                                        /* String for requested attributes */
-                       make_str[256];  /* Escaped ppd-make string */
 
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppds(%p[%d])", con, con->http.fd);
@@ -5922,7 +6101,14 @@ get_ppds(cupsd_client_t *con)            /* I - Client connection */
   */
 
   limit     = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER);
+  device    = ippFindAttribute(con->request, "ppd-device-id", IPP_TAG_TEXT);
+  language  = ippFindAttribute(con->request, "ppd-natural-language",
+                               IPP_TAG_LANGUAGE);
   make      = ippFindAttribute(con->request, "ppd-make", IPP_TAG_TEXT);
+  model     = ippFindAttribute(con->request, "ppd-make-and-model",
+                               IPP_TAG_TEXT);
+  product   = ippFindAttribute(con->request, "ppd-product", IPP_TAG_TEXT);
+  psversion = ippFindAttribute(con->request, "ppd-psversion", IPP_TAG_TEXT);
   requested = ippFindAttribute(con->request, "requested-attributes",
                                IPP_TAG_KEYWORD);
 
@@ -5931,16 +6117,47 @@ get_ppds(cupsd_client_t *con)           /* I - Client connection */
   else
     strlcpy(requested_str, "requested-attributes=all", sizeof(requested_str));
 
+  if (device)
+    url_encode_attr(device, device_str, sizeof(device_str));
+  else
+    device_str[0] = '\0';
+
+  if (language)
+    url_encode_attr(language, language_str, sizeof(language_str));
+  else
+    language_str[0] = '\0';
+
   if (make)
     url_encode_attr(make, make_str, sizeof(make_str));
   else
     make_str[0] = '\0';
 
+  if (model)
+    url_encode_attr(model, model_str, sizeof(model_str));
+  else
+    model_str[0] = '\0';
+
+  if (product)
+    url_encode_attr(product, product_str, sizeof(product_str));
+  else
+    product_str[0] = '\0';
+
+  if (psversion)
+    url_encode_attr(psversion, psversion_str, sizeof(psversion_str));
+  else
+    psversion_str[0] = '\0';
+
   snprintf(command, sizeof(command), "%s/daemon/cups-driverd", ServerBin);
-  snprintf(options, sizeof(options), "list+%d+%d+%s%s%s",
+  snprintf(options, sizeof(options), "list+%d+%d+%s%s%s%s%s%s%s%s%s%s%s%s%s",
            con->request->request.op.request_id,
            limit ? limit->values[0].integer : 0,
-          requested_str, make ? "%20" : "", make_str);
+          requested_str,
+          device ? "%20" : "", device_str,
+          language ? "%20" : "", language_str,
+          make ? "%20" : "", make_str,
+          model ? "%20" : "", model_str,
+          product ? "%20" : "", product_str,
+          psversion ? "%20" : "", psversion_str);
 
   if (cupsdSendCommand(con, command, options, 0))
   {
@@ -7621,6 +7838,9 @@ renew_subscription(
   cupsdSaveAllSubscriptions();
 
   con->response->request.status.status_code = IPP_OK;
+
+  ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER,
+                "notify-lease-duration", sub->lease);
 }
 
 
@@ -9221,8 +9441,7 @@ url_encode_attr(ipp_attribute_t *attr,    /* I - Attribute */
 {
   int  i;                              /* Looping var */
   char *bufptr,                        /* Pointer into buffer */
-       *bufend,                        /* End of buffer */
-       *valptr;                        /* Pointer into value */
+       *bufend;                        /* End of buffer */
 
 
   strlcpy(buffer, attr->name, bufsize);
@@ -9244,25 +9463,8 @@ url_encode_attr(ipp_attribute_t *attr,   /* I - Attribute */
 
     *bufptr++ = '\'';
 
-    for (valptr = attr->values[i].string.text;
-         *valptr && bufptr < bufend;
-        valptr ++)
-      if (*valptr == ' ')
-      {
-        if (bufptr >= (bufend - 2))
-         break;
-
-        *bufptr++ = '%';
-       *bufptr++ = '2';
-       *bufptr++ = '0';
-      }
-      else if (*valptr == '\'' || *valptr == '\\')
-      {
-        *bufptr++ = '\\';
-        *bufptr++ = *valptr;
-      }
-      else
-        *bufptr++ = *valptr;
+    bufptr = url_encode_string(attr->values[i].string.text,
+                               bufptr, bufend - bufptr + 1);
 
     if (bufptr >= bufend)
       break;
@@ -9274,6 +9476,55 @@ url_encode_attr(ipp_attribute_t *attr,   /* I - Attribute */
 }
 
 
+/*
+ * 'url_encode_string()' - URL-encode a string.
+ */
+
+static char *                          /* O - End of string */
+url_encode_string(const char *s,       /* I - String */
+                  char       *buffer,  /* I - String buffer */
+                 int        bufsize)   /* I - Size of buffer */
+{
+  char *bufptr,                        /* Pointer into buffer */
+       *bufend;                        /* End of buffer */
+  static const char *hex = "0123456789ABCDEF";
+                                       /* Hex digits */
+
+
+  bufptr = buffer;
+  bufend = buffer + bufsize - 1;
+
+  while (*s && bufptr < bufend)
+  {
+    if (*s == ' ' || *s == '%')
+    {
+      if (bufptr >= (bufend - 2))
+       break;
+
+      *bufptr++ = '%';
+      *bufptr++ = hex[(*s >> 4) & 15];
+      *bufptr++ = hex[*s & 15];
+
+      s ++;
+    }
+    else if (*s == '\'' || *s == '\\')
+    {
+      if (bufptr >= (bufend - 1))
+       break;
+
+      *bufptr++ = '\\';
+      *bufptr++ = *s++;
+    }
+    else
+      *bufptr++ = *s++;
+  }
+
+  *bufptr = '\0';
+
+  return (bufptr);
+}
+
+
 /*
  * 'user_allowed()' - See if a user is allowed to print to a queue.
  */
@@ -9485,5 +9736,5 @@ validate_user(cupsd_job_t    *job,        /* I - Job */
 
 
 /*
- * End of "$Id: ipp.c 6433 2007-04-02 21:50:50Z mike $".
+ * End of "$Id: ipp.c 6508 2007-05-03 20:07:14Z mike $".
  */
index 96513a2f55ea3b9ba318e58e699e16866fa11bb0..90434af16d1ed3417efbcdef3c39b224a354aeab 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: job.c 6433 2007-04-02 21:50:50Z mike $"
+ * "$Id: job.c 6462 2007-04-23 19:25:13Z mike $"
  *
  *   Job management routines for the Common UNIX Printing System (CUPS).
  *
@@ -2721,6 +2721,7 @@ start_job(cupsd_job_t     *job,           /* I - Job ID */
       if ((!strcmp(attr->name, "page-label") ||
            !strcmp(attr->name, "page-border") ||
            !strncmp(attr->name, "number-up", 9) ||
+          !strcmp(attr->name, "page-ranges") ||
           !strcmp(attr->name, "page-set") ||
           !strcasecmp(attr->name, "AP_FIRSTPAGE_InputSlot") ||
           !strcasecmp(attr->name, "AP_FIRSTPAGE_ManualFeed")) &&
@@ -3323,6 +3324,8 @@ start_job(cupsd_job_t     *job,           /* I - Job ID */
   cupsdClosePipe(job->status_pipes);
   cupsdStatBufDelete(job->status_buffer);
 
+  job->status_buffer = NULL;
+
   cupsArrayDelete(filters);
 
   if (printer->remote && job->num_files > 1)
@@ -3549,5 +3552,5 @@ update_job(cupsd_job_t *job)      /* I - Job to check */
 
 
 /*
- * End of "$Id: job.c 6433 2007-04-02 21:50:50Z mike $".
+ * End of "$Id: job.c 6462 2007-04-23 19:25:13Z mike $".
  */
index 11c3cbcfe1a9d0134e369c115ff6b3520400a8df..2c7c573e2ae90b23a0d8871e1fa9a72000a65b93 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * "$Id: log.c 6328 2007-03-12 14:45:42Z mike $"
+ * "$Id: log.c 6492 2007-04-30 19:31:36Z mike $"
  *
  *   Log file routines for the Common UNIX Printing System (CUPS).
  *
- *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
+ *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
  *   property of Easy Software Products and are protected by Federal
@@ -546,10 +546,23 @@ check_log_file(cups_file_t **lf,  /* IO - Log file */
 
     if ((*lf = cupsFileOpen(filename, "a")) == NULL)
     {
-      syslog(LOG_ERR, "Unable to open log file \"%s\" - %s", filename,
-             strerror(errno));
+     /*
+      * If the file is in CUPS_LOGDIR then try to create a missing directory...
+      */
 
-      return (0);
+      if (!strncmp(filename, CUPS_LOGDIR, strlen(CUPS_LOGDIR)))
+      {
+        cupsdCheckPermissions(CUPS_LOGDIR, NULL, 0755, RunUser, Group, 1, -1);
+
+        *lf = cupsFileOpen(filename, "a");
+      }
+
+      if (*lf == NULL)
+      {
+       syslog(LOG_ERR, "Unable to open log file \"%s\" - %s", filename,
+              strerror(errno));
+       return (0);
+      }
     }
 
     if (strncmp(filename, "/dev/", 5))
@@ -603,5 +616,5 @@ check_log_file(cups_file_t **lf,    /* IO - Log file */
 
 
 /*
- * End of "$Id: log.c 6328 2007-03-12 14:45:42Z mike $".
+ * End of "$Id: log.c 6492 2007-04-30 19:31:36Z mike $".
  */
index f17969eea5880742d446ca2b7e201f1f203cf62a..79d70912e84dab19e5c3f2814245a913bfef5387 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: main.c 6365 2007-03-19 20:56:57Z mike $"
+ * "$Id: main.c 6493 2007-04-30 19:33:31Z mike $"
  *
  *   Scheduler main loop for the Common UNIX Printing System (CUPS).
  *
  *   launchd_checkin()         - Check-in with launchd and collect the
  *                               listening fds.
  *   launchd_checkout()        - Check-out with launchd.
- *   launchd_create_dict()     - Create a dictionary representing the launchd
- *                              config file org.cups.cupsd.plist.
- *   launchd_sync_conf()       - Re-write the launchd config file
- *                              org.cups.cupsd.plist based on cupsd.conf.
  *   parent_handler()          - Catch USR1/CHLD signals...
  *   process_children()        - Process all dead children...
  *   sigchld_handler()         - Handle 'child' signals from old processes.
@@ -93,8 +89,6 @@
 #ifdef HAVE_LAUNCHD
 static void            launchd_checkin(void);
 static void            launchd_checkout(void);
-static CFDictionaryRef launchd_create_dict(void);
-static int             launchd_sync_conf(void);
 #endif /* HAVE_LAUNCHD */
 static void            parent_handler(int sig);
 static void            process_children(void);
@@ -120,13 +114,6 @@ static int         dead_children = 0;
 static int             stop_scheduler = 0;
                                        /* Should the scheduler stop? */
 
-#ifdef HAVE_LAUNCHD
-static CFURLRef                launchd_conf_url = NULL;
-                                       /* org.cups.cupsd.plist url */
-static CFDictionaryRef launchd_conf_dict = NULL;
-                                       /* org.cups.cupsd.plist dict */
-#endif /* HAVE_LAUNCHD */
-
 #if defined(__APPLE__) && defined(HAVE_DLFCN_H)
 static const char *PSQLibPath = "/usr/lib/libPrintServiceQuota.dylib";
 static const char *PSQLibFuncName = "PSQUpdateQuota";
@@ -366,7 +353,7 @@ main(int  argc,                             /* I - Number of command-line args */
 
     getrlimit(RLIMIT_NOFILE, &limit);
 
-    for (i = 0; i < limit.rlim_cur; i ++)
+    for (i = 0; i < limit.rlim_cur && i < 1024; i ++)
       close(i);
 #endif /* DEBUG */
   }
@@ -420,14 +407,7 @@ main(int  argc,                            /* I - Number of command-line args */
   if (Launchd)
   {
    /*
-    * If we were started by launchd, make sure the cupsd plist file contains
-    * the same listeners as cupsd.conf.
-    */
-
-    launchd_sync_conf();
-
-   /*
-    * Then get the file descriptors from launchd...
+    * If we were started by launchd get the listen sockets file descriptors...
     */
 
     launchd_checkin();
@@ -638,7 +618,10 @@ main(int  argc,                            /* I - Number of command-line args */
 #if HAVE_LAUNCHD
        if (Launchd)
        {
-         launchd_sync_conf();
+        /*
+         * If we were started by launchd get the listen sockets file descriptors...
+         */
+
          launchd_checkin();
        }
 #endif /* HAVE_LAUNCHD */
@@ -952,21 +935,27 @@ main(int  argc,                           /* I - Number of command-line args */
 
 #ifdef HAVE_LAUNCHD
  /*
-  * Update the launchd config file as needed...
+  * Update the launchd KeepAlive file as needed...
   */
 
   if (Launchd)
-  {
     launchd_checkout();
-    launchd_sync_conf();
+#endif /* HAVE_LAUNCHD */
 
-    if (launchd_conf_url)
-      CFRelease(launchd_conf_url);
+#ifdef __APPLE__
+#ifdef HAVE_DLFCN_H
+ /* 
+  * Unload Print Service quota enforcement library (X Server only) 
+  */
 
-    if (launchd_conf_dict)
-      CFRelease(launchd_conf_dict);
+  PSQUpdateQuotaProc = NULL;
+  if (PSQLibRef)
+  {
+    dlclose(PSQLibRef);
+    PSQLibRef = NULL;
   }
-#endif /* HAVE_LAUNCHD */
+#endif /* HAVE_DLFCN_H */
+#endif /* __APPLE__ */
 
 #ifdef __sgi
  /*
@@ -1335,38 +1324,6 @@ launchd_checkin(void)
     }
   }
 
- /*
-  * Collect the browse socket (if there is one)...
-  */
-
-  if ((ld_array = launch_data_dict_lookup(ld_sockets, "BrowseSockets")))
-  {
-    if (launch_data_get_type(ld_array) == LAUNCH_DATA_ARRAY)
-    {
-      if ((tmp = launch_data_array_get_index(ld_array, 0)))
-      {
-       if (launch_data_get_type(tmp) == LAUNCH_DATA_FD)
-       {
-         if (BrowseSocket != -1)
-           close(BrowseSocket);
-
-         BrowseSocket = launch_data_get_fd(tmp);
-       }
-       else
-         cupsdLogMessage(CUPSD_LOG_WARN,
-                         "launchd_checkin: BrowseSocket not a fd!");
-     }
-     else
-       cupsdLogMessage(CUPSD_LOG_WARN,
-                      "launchd_checkin: BrowseSockets is an empty array!");
-   }
-   else
-     cupsdLogMessage(CUPSD_LOG_WARN,
-                     "launchd_checkin: BrowseSockets is not an array!");
-  }
-  else
-    cupsdLogMessage(CUPSD_LOG_DEBUG, "launchd_checkin: No BrowseSockets");
-
   launch_data_free(ld_msg);
   launch_data_free(ld_resp);
 }
@@ -1408,340 +1365,6 @@ launchd_checkout(void)
   }
 }
 
-
-/*
- * 'launchd_create_dict()' - Create a dictionary representing the launchd
- *                          config file org.cups.cupsd.plist.
- */
-
-static CFDictionaryRef                 /* O - CFDictionary */
-launchd_create_dict(void)
-{
-  int                  portnum;        /* Port number */
-  bool                 runatload;      /* Run at load? */
-  CFMutableDictionaryRef cupsd_dict,   /* org.cups.cupsd.plist dictionary */
-                       keepalive,      /* KeepAlive dictionary */
-                       pathstate,      /* PathState dictionary */
-                       sockets,        /* Sockets dictionary */
-                       listener;       /* Listener dictionary */
-  CFMutableArrayRef    array;          /* Array */
-  CFNumberRef          socket_mode;    /* Domain socket mode bits */
-  CFStringRef          socket_path;    /* Domain socket path */
-  CFTypeRef            value;          /* CF values */
-  cupsd_listener_t     *lis;           /* Current listening socket */
-  struct servent       *service;       /* Services data base entry */
-  char                 temp[1024];     /* Temporary buffer for value */
-
-
-  if ((cupsd_dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
-                               &kCFTypeDictionaryKeyCallBacks,
-                               &kCFTypeDictionaryValueCallBacks)) == NULL)
-    return (NULL);
-
-  CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_LABEL),
-                      CFSTR("org.cups.cupsd"));
-  CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_ONDEMAND),
-                      kCFBooleanTrue);
-
- /*
-  * Use run-at-load and/or KeepAlive if there are active jobs, polling or
-  * shared printers to advertise...
-  */
-
-  if ((keepalive = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
-                               &kCFTypeDictionaryKeyCallBacks,
-                               &kCFTypeDictionaryValueCallBacks)) != NULL)
-  {
-    if ((pathstate = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
-                               &kCFTypeDictionaryKeyCallBacks,
-                               &kCFTypeDictionaryValueCallBacks)) != NULL)
-    {
-      CFDictionaryAddValue(pathstate, CFSTR(CUPS_KEEPALIVE), kCFBooleanTrue);
-      CFDictionaryAddValue(keepalive, CFSTR(LAUNCH_JOBKEY_PATHSTATE),
-                          pathstate);
-    }
-
-    CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_KEEPALIVE),
-                        keepalive);
-  }
-
-  runatload = (cupsArrayCount(ActiveJobs) || NumPolled || 
-              (Browsing && BrowseLocalProtocols && 
-               NumBrowsers && cupsArrayCount(Printers))) ? true : false;
-
-  CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_RUNATLOAD),
-                      runatload ? kCFBooleanTrue : kCFBooleanFalse);
-  CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_SERVICEIPC),
-                      kCFBooleanTrue);
-
-  if ((array = CFArrayCreateMutable(kCFAllocatorDefault, 2,
-                                   &kCFTypeArrayCallBacks)) != NULL)
-  {
-    CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_PROGRAMARGUMENTS),
-                        array);
-    CFArrayAppendValue(array, CFSTR("/usr/sbin/cupsd"));
-    CFArrayAppendValue(array, CFSTR("-l"));
-    CFRelease(array);
-  }
-
- /*
-  * Add a sockets dictionary...
-  */
-
-  if ((sockets = (CFMutableDictionaryRef)CFDictionaryCreateMutable(
-                             kCFAllocatorDefault, 0,
-                             &kCFTypeDictionaryKeyCallBacks,
-                             &kCFTypeDictionaryValueCallBacks)) != NULL)
-  {
-    CFDictionaryAddValue(cupsd_dict, CFSTR(LAUNCH_JOBKEY_SOCKETS), sockets);
-
-   /*
-    * Add a Listeners array to the sockets dictionary...
-    */
-
-    if ((array = CFArrayCreateMutable(kCFAllocatorDefault, 0,
-                                     &kCFTypeArrayCallBacks)) != NULL)
-    {
-      CFDictionaryAddValue(sockets, CFSTR("Listeners"), array);
-
-     /*
-      * For each listener add a dictionary to the listeners array...
-      */
-
-      for (lis = (cupsd_listener_t *)cupsArrayFirst(Listeners);
-          lis;
-          lis = (cupsd_listener_t *)cupsArrayNext(Listeners))
-      {
-       if ((listener = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
-                             &kCFTypeDictionaryKeyCallBacks,
-                             &kCFTypeDictionaryValueCallBacks)) != NULL)
-       {
-         CFArrayAppendValue(array, listener);
-
-#  ifdef AF_LOCAL
-         if (lis->address.addr.sa_family == AF_LOCAL)
-         {
-           if ((socket_path = CFStringCreateWithCString(kCFAllocatorDefault,
-                                     lis->address.un.sun_path,
-                                     kCFStringEncodingUTF8)))
-           {
-             CFDictionaryAddValue(listener,
-                                  CFSTR(LAUNCH_JOBSOCKETKEY_PATHNAME),
-                                  socket_path);
-             CFRelease(socket_path);
-           }
-           portnum = 0140777; /* (S_IFSOCK|S_IRWXU|S_IRWXG|S_IRWXO) or *
-                               * 49663d decimal                        */
-           if ((socket_mode = CFNumberCreate(kCFAllocatorDefault,
-                                             kCFNumberIntType, &portnum)))
-           {
-             CFDictionaryAddValue(listener, CFSTR("SockPathMode"),
-                                  socket_mode);
-             CFRelease(socket_mode);
-           }
-         }
-         else
-#  endif /* AF_LOCAL */
-         {
-#  ifdef AF_INET6
-           if (lis->address.addr.sa_family == AF_INET6)
-           {
-             CFDictionaryAddValue(listener,
-                                  CFSTR(LAUNCH_JOBSOCKETKEY_FAMILY),
-                                  CFSTR("IPv6"));
-             portnum = lis->address.ipv6.sin6_port;
-           }
-           else
-#  endif /* AF_INET6 */
-           {
-             CFDictionaryAddValue(listener,
-                                  CFSTR(LAUNCH_JOBSOCKETKEY_FAMILY),
-                                  CFSTR("IPv4"));
-             portnum = lis->address.ipv4.sin_port;
-           }
-
-           if ((service = getservbyport(portnum, NULL)))
-             value = CFStringCreateWithCString(kCFAllocatorDefault,
-                                               service->s_name,
-                                               kCFStringEncodingUTF8);
-           else
-             value = CFNumberCreate(kCFAllocatorDefault,
-                                    kCFNumberIntType, &portnum);
-
-           if (value)
-           {
-             CFDictionaryAddValue(listener,
-                                  CFSTR(LAUNCH_JOBSOCKETKEY_SERVICENAME),
-                                  value);
-             CFRelease(value);
-           }   
-
-           httpAddrString(&lis->address, temp, sizeof(temp));
-           if ((value = CFStringCreateWithCString(kCFAllocatorDefault, temp,
-                                                  kCFStringEncodingUTF8)))
-           {
-             CFDictionaryAddValue(listener,
-                                  CFSTR(LAUNCH_JOBSOCKETKEY_NODENAME),
-                                  value);
-             CFRelease(value);
-           }
-         }
-
-         CFRelease(listener);
-       }
-      }
-
-      CFRelease(array);
-    }
-
-   /*
-    * Add the BrowseSocket to the sockets dictionary...
-    */
-
-    if (Browsing && (BrowseRemoteProtocols & BROWSE_CUPS))
-    {
-      if ((array = CFArrayCreateMutable(kCFAllocatorDefault, 0,
-                                       &kCFTypeArrayCallBacks)) != NULL)
-      {
-       CFDictionaryAddValue(sockets, CFSTR("BrowseSockets"), array);
-
-       if ((listener = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
-                               &kCFTypeDictionaryKeyCallBacks,
-                               &kCFTypeDictionaryValueCallBacks)) != NULL)
-       {
-         CFArrayAppendValue(array, listener);
-
-         CFDictionaryAddValue(listener, CFSTR(LAUNCH_JOBSOCKETKEY_FAMILY),
-                              CFSTR("IPv4"));
-         CFDictionaryAddValue(listener, CFSTR(LAUNCH_JOBSOCKETKEY_TYPE),
-                              CFSTR("dgram"));
-
-         if ((service = getservbyport(BrowsePort, NULL)))
-           value = CFStringCreateWithCString(kCFAllocatorDefault,
-                                             service->s_name,
-                                             kCFStringEncodingUTF8);
-         else
-           value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType,
-                                  &BrowsePort);
-
-         CFDictionaryAddValue(listener,
-                              CFSTR(LAUNCH_JOBSOCKETKEY_SERVICENAME), value);
-         CFRelease(value);
-
-         CFRelease(listener);
-       }
-
-       CFRelease(array);
-      }
-    }
-
-    CFRelease(sockets);
-  }
-
-  return (cupsd_dict);
-}
-
-
-/*
- * 'launchd_sync_conf()' - Rewrite the launchd config file
- *                        org.cups.cupsd.plist based on cupsd.conf.
- */
-
-static int                             /* O - 1 if the file was updated */
-launchd_sync_conf(void)
-{
-  SInt32               errorCode;      /* Error code */
-  CFDataRef            resourceData;   /* XML property list */
-  CFDictionaryRef      cupsd_dict;     /* New org.cups.cupsd.plist dict */
-
-
- /*
-  * If needed reconstitute the existing org.cups.cupsd.plist...
-  */
-
-  if (!launchd_conf_url && 
-      !(launchd_conf_url = CFURLCreateFromFileSystemRepresentation(
-                               kCFAllocatorDefault,
-                               (const unsigned char *)LaunchdConf,
-                               strlen(LaunchdConf), false)))
-  {
-    cupsdLogMessage(CUPSD_LOG_ERROR, "launchd_sync_conf: "
-                   "Unable to create file URL for \"%s\"\n", LaunchdConf);
-    return (0);
-  }
-
-  if (!launchd_conf_dict)
-  {
-    if (CFURLCreateDataAndPropertiesFromResource(NULL, launchd_conf_url, 
-                               &resourceData, NULL, NULL, &errorCode))
-    {
-      launchd_conf_dict = CFPropertyListCreateFromXMLData(NULL, resourceData,
-                                             kCFPropertyListImmutable, NULL);
-      CFRelease(resourceData);
-    }
-
-    if (!launchd_conf_dict)
-    {
-      cupsdLogMessage(CUPSD_LOG_ERROR, "launchd_sync_conf: "
-                     "Unable to create dictionary for \"%s\"\n", LaunchdConf);
-    }
-  }
-
- /*
-  * Create a new org.cups.cupsd.plist dictionary...
-  */
-
-  if ((cupsd_dict = launchd_create_dict()) == NULL)
-  {
-    cupsdLogMessage(CUPSD_LOG_ERROR, "launchd_sync_conf: "
-                   "Unable to create file URL for \"%s\"\n", LaunchdConf);
-    return (0);
-  }
-
- /*
-  * If the dictionaries are different write a new org.cups.cupsd.plist...
-  */
-
-  if (!CFEqual(cupsd_dict, launchd_conf_dict))
-  {
-    if ((resourceData = CFPropertyListCreateXMLData(kCFAllocatorDefault,
-                                                   cupsd_dict)))
-    {
-      if (CFURLWriteDataAndPropertiesToResource(launchd_conf_url, resourceData,
-                                                NULL, &errorCode))
-      {
-       /*
-        * The new cupsd dictionary becomes the on-disk launchd dictionary...
-        */
-
-       if (launchd_conf_dict)
-         CFRelease(launchd_conf_dict);
-
-       launchd_conf_dict = cupsd_dict;
-      }
-      else
-      {
-       cupsdLogMessage(CUPSD_LOG_WARN,
-                       "launchd_sync_conf: "
-                       "CFURLWriteDataAndPropertiesToResource(\"%s\") "
-                       "failed: %d\n",
-                       LaunchdConf, (int)errorCode);
-
-       CFRelease(cupsd_dict);
-      }
-  
-      CFRelease(resourceData);
-    }
-
-   /*
-    * Let the caller know we updated the file...
-    */
-
-    return (1);
-  }
-
-  return (0);
-}
 #endif /* HAVE_LAUNCHD */
 
 
@@ -2155,5 +1778,5 @@ usage(int status)                 /* O - Exit status */
 
 
 /*
- * End of "$Id: main.c 6365 2007-03-19 20:56:57Z mike $".
+ * End of "$Id: main.c 6493 2007-04-30 19:33:31Z mike $".
  */
index 1934383ec2ac16cbc9402d77db0224f8ec4099df..411efa49522a098c065bfb90970953850365ffab 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: printers.c 6436 2007-04-02 23:24:02Z mike $"
+ * "$Id: printers.c 6501 2007-04-30 21:53:15Z mike $"
  *
  *   Printer routines for the Common UNIX Printing System (CUPS).
  *
@@ -26,6 +26,7 @@
  *   cupsdAddPrinter()           - Add a printer to the system.
  *   cupsdAddPrinterHistory()    - Add the current printer state to the history.
  *   cupsdAddPrinterUser()       - Add a user to the ACL.
+ *   cupsdCreateCommonData()     - Create the common printer data.
  *   cupsdDeleteAllPrinters()    - Delete all printers from the system.
  *   cupsdDeletePrinter()        - Delete a printer from the system.
  *   cupsdFindPrinter()          - Find a printer in the list.
@@ -266,7 +267,7 @@ cupsdCreateCommonData(void)
                        *notifier;      /* Current notifier */
   static const int nups[] =            /* number-up-supported values */
                { 1, 2, 4, 6, 9, 16 };
-  static const ipp_orient_t orients[4] =/* orientation-requested-supported values */
+  static const int orients[4] =/* orientation-requested-supported values */
                {
                  IPP_PORTRAIT,
                  IPP_LANDSCAPE,
@@ -289,7 +290,7 @@ cupsdCreateCommonData(void)
                  "1.0",
                  "1.1"
                };
-  static const ipp_op_t        ops[] =         /* operations-supported values */
+  static const int     ops[] =         /* operations-supported values */
                {
                  IPP_PRINT_JOB,
                  IPP_VALIDATE_JOB,
@@ -413,6 +414,10 @@ cupsdCreateCommonData(void)
   /* copies-supported */
   ippAddRange(CommonData, IPP_TAG_PRINTER, "copies-supported", 1, MaxCopies);
 
+  /* cups-version */
+  ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_TEXT, "cups-version",
+               NULL, CUPS_SVERSION + 6);
+
   /* generated-natural-language-supported */
   ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE,
                "generated-natural-language-supported", NULL, DefaultLanguage);
@@ -545,11 +550,11 @@ cupsdCreateCommonData(void)
   /* operations-supported */
   ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
                  "operations-supported",
-                 sizeof(ops) / sizeof(ops[0]) + JobFiles - 1, (int *)ops);
+                 sizeof(ops) / sizeof(ops[0]) + JobFiles - 1, ops);
 
   /* orientation-requested-supported */
   ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM,
-                 "orientation-requested-supported", 4, (int *)orients);
+                 "orientation-requested-supported", 4, orients);
 
   /* page-ranges-supported */
   ippAddBoolean(CommonData, IPP_TAG_PRINTER, "page-ranges-supported", 1);
@@ -1651,7 +1656,7 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
   ipp_attribute_t *attr;               /* Attribute data */
   ipp_value_t  *val;                   /* Attribute value */
   int          num_finishings;         /* Number of finishings */
-  ipp_finish_t finishings[5];          /* finishings-supported values */
+  int          finishings[5];          /* finishings-supported values */
   cups_option_t        *option;                /* Current printer option */
   static const char * const sides[3] = /* sides-supported values */
                {
@@ -2288,7 +2293,7 @@ cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */
       }
 
       ippAddIntegers(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
-                     "finishings-supported", num_finishings, (int *)finishings);
+                     "finishings-supported", num_finishings, finishings);
       ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM,
                     "finishings-default", IPP_FINISHINGS_NONE);
     }
@@ -3708,5 +3713,5 @@ write_irix_state(cupsd_printer_t *p)      /* I - Printer to update */
 
 
 /*
- * End of "$Id: printers.c 6436 2007-04-02 23:24:02Z mike $".
+ * End of "$Id: printers.c 6501 2007-04-30 21:53:15Z mike $".
  */
index ed1becfb5ae2afd553ffa6e2d804f33cb3456085..6f013c56a503e5bf5b231483fc4e1489d56370d8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * "$Id: cupstestppd.c 6444 2007-04-04 22:13:58Z mike $"
+ * "$Id: cupstestppd.c 6509 2007-05-03 22:58:41Z mike $"
  *
  *   PPD test program for the Common UNIX Printing System (CUPS).
  *
 #include <sys/stat.h>
 
 
+/*
+ * Error warning overrides...
+ */
+
+enum
+{
+  WARN_NONE = 0,
+  WARN_CONSTRAINTS = 1,
+  WARN_DEFAULTS = 2,
+  WARN_FILTERS = 4,
+  WARN_TRANSLATIONS = 8,
+  WARN_ALL = 15
+};
+
+
 /*
  * Error codes...
  */
@@ -77,10 +92,16 @@ enum
  */
 
 void   check_basics(const char *filename);
+int    check_constraints(ppd_file_t *ppd, int errors, int verbose, int warn);
+int    check_defaults(ppd_file_t *ppd, int errors, int verbose, int warn);
+int    check_filters(ppd_file_t *ppd, const char *root, int errors,
+                     int verbose, int warn);
+int    check_translations(ppd_file_t *ppd, int errors, int verbose, int warn);
 void   show_conflicts(ppd_file_t *ppd);
 void   usage(void);
 int    valid_utf8(const char *s);
 
+
 /*
  * 'main()' - Main entry for test program.
  */
@@ -95,18 +116,15 @@ main(int  argc,                            /* I - Number of command-line args */
   const char   *ptr;                   /* Pointer into string */
   int          files;                  /* Number of files */
   int          verbose;                /* Want verbose output? */
+  int          warn;                   /* Which errors to just warn about */
   int          status;                 /* Exit status */
   int          errors;                 /* Number of conformance errors */
   int          ppdversion;             /* PPD spec version in PPD file */
   ppd_status_t error;                  /* Status of ppdOpen*() */
   int          line;                   /* Line number for error */
   struct stat  statbuf;                /* File information */
-  char         super[16],              /* Super-type for filter */
-               type[256],              /* Type for filter */
-               program[256],           /* Program/filter name */
-               pathprog[1024],         /* Complete path to program/filter */
+  char         pathprog[1024],         /* Complete path to program/filter */
                *root;                  /* Root directory */
-  int          cost;                   /* Cost of filter */
   int          xdpi,                   /* X resolution */
                ydpi;                   /* Y resolution */
   ppd_file_t   *ppd;                   /* PPD file record */
@@ -117,7 +135,6 @@ main(int  argc,                             /* I - Number of command-line args */
   ppd_group_t  *group2;                /* UI group */
   ppd_option_t *option2;               /* Standard UI option */
   ppd_choice_t *choice;                /* Standard UI option choice */
-  ppd_const_t  *c;                     /* Current constraint */
   static char  *uis[] = { "BOOLEAN", "PICKONE", "PICKMANY" };
   static char  *sections[] = { "ANY", "DOCUMENT", "EXIT",
                                 "JCL", "PAGE", "PROLOG" };
@@ -136,6 +153,7 @@ main(int  argc,                             /* I - Number of command-line args */
   files   = 0;
   status  = ERROR_NONE;
   root    = "";
+  warn    = WARN_NONE;
 
   for (i = 1; i < argc; i ++)
     if (argv[i][0] == '-' && argv[i][1])
@@ -152,6 +170,28 @@ main(int  argc,                            /* I - Number of command-line args */
               root = argv[i];
              break;
 
+         case 'W' :                    /* Turn errors into warnings  */
+             i ++;
+
+             if (i >= argc)
+               usage();
+
+              if (!strcmp(argv[i], "none"))
+               warn = WARN_NONE;
+             else if (!strcmp(argv[i], "constraints"))
+               warn |= WARN_CONSTRAINTS;
+             else if (!strcmp(argv[i], "defaults"))
+               warn |= WARN_DEFAULTS;
+             else if (!strcmp(argv[i], "filters"))
+               warn |= WARN_FILTERS;
+             else if (!strcmp(argv[i], "translations"))
+               warn |= WARN_TRANSLATIONS;
+             else if (!strcmp(argv[i], "all"))
+               warn = WARN_ALL;
+             else
+               usage();
+             break;
+
          case 'q' :                    /* Quiet mode */
              if (verbose > 0)
              {
@@ -328,49 +368,8 @@ main(int  argc,                            /* I - Number of command-line args */
       * Look for default keywords with no matching option...
       */
 
-      for (j = 0; j < ppd->num_attrs; j ++)
-      {
-       attr = ppd->attrs[j];
-
-        if (!strcmp(attr->name, "DefaultColorSpace") ||
-           !strcmp(attr->name, "DefaultFont") ||
-           !strcmp(attr->name, "DefaultImageableArea") ||
-           !strcmp(attr->name, "DefaultOutputOrder") ||
-           !strcmp(attr->name, "DefaultPaperDimension") ||
-           !strcmp(attr->name, "DefaultResolution") ||
-           !strcmp(attr->name, "DefaultTransfer"))
-         continue;
-
-       if (!strncmp(attr->name, "Default", 7))
-       {
-         if ((option = ppdFindOption(ppd, attr->name + 7)) != NULL &&
-              strcmp(attr->value, "Unknown"))
-         {
-          /*
-           * Check that the default option value matches a choice...
-           */
-
-           for (k = 0; k < option->num_choices; k ++)
-             if (!strcmp(option->choices[k].choice, attr->value))
-               break;
-
-            if (k >= option->num_choices)
-           {
-             if (verbose >= 0)
-             {
-               if (!errors && !verbose)
-                 _cupsLangPuts(stdout, _(" FAIL\n"));
-
-               _cupsLangPrintf(stdout,
-                               _("      **FAIL**  %s %s does not exist!\n"),
-                               attr->name, attr->value);
-              }
-
-             errors ++;
-           }
-         }
-       }
-      }
+      if (!(warn & WARN_DEFAULTS))
+        errors = check_defaults(ppd, errors, verbose, 0);
 
       if ((attr = ppdFindAttr(ppd, "DefaultImageableArea", NULL)) == NULL)
       {
@@ -380,14 +379,14 @@ main(int  argc,                           /* I - Number of command-line args */
            _cupsLangPuts(stdout, _(" FAIL\n"));
 
          _cupsLangPuts(stdout,
-                       _("      **FAIL**  REQUIRED DefaultImageableArea\n"
+                       _("      **FAIL**  REQUIRED DefaultImageableArea\n"
                          "                REF: Page 102, section 5.15.\n"));
-        }
+       }
 
        errors ++;
       }
       else if (ppdPageSize(ppd, attr->value) == NULL &&
-               strcmp(attr->value, "Unknown"))
+              strcmp(attr->value, "Unknown"))
       {
        if (verbose >= 0)
        {
@@ -395,10 +394,10 @@ main(int  argc,                           /* I - Number of command-line args */
            _cupsLangPuts(stdout, _(" FAIL\n"));
 
          _cupsLangPrintf(stdout,
-                         _("      **FAIL**  BAD DefaultImageableArea %s!\n"
+                         _("      **FAIL**  BAD DefaultImageableArea %s!\n"
                            "                REF: Page 102, section 5.15.\n"),
                          attr->value);
-        }
+       }
 
        errors ++;
       }
@@ -416,14 +415,14 @@ main(int  argc,                           /* I - Number of command-line args */
            _cupsLangPuts(stdout, _(" FAIL\n"));
 
          _cupsLangPuts(stdout,
-                       _("      **FAIL**  REQUIRED DefaultPaperDimension\n"
+                       _("      **FAIL**  REQUIRED DefaultPaperDimension\n"
                          "                REF: Page 103, section 5.15.\n"));
-        }
+       }
 
        errors ++;
       }
       else if (ppdPageSize(ppd, attr->value) == NULL &&
-               strcmp(attr->value, "Unknown"))
+              strcmp(attr->value, "Unknown"))
       {
        if (verbose >= 0)
        {
@@ -431,10 +430,10 @@ main(int  argc,                           /* I - Number of command-line args */
            _cupsLangPuts(stdout, _(" FAIL\n"));
 
          _cupsLangPrintf(stdout,
-                         _("      **FAIL**  BAD DefaultPaperDimension %s!\n"
+                         _("      **FAIL**  BAD DefaultPaperDimension %s!\n"
                            "                REF: Page 103, section 5.15.\n"),
                          attr->value);
-        }
+       }
 
        errors ++;
       }
@@ -450,8 +449,8 @@ main(int  argc,                             /* I - Number of command-line args */
 
          if (option->defchoice[0])
          {
-            if (ppdFindChoice(option, option->defchoice) == NULL &&
-               strcmp(option->defchoice, "Unknown"))
+           if (ppdFindChoice(option, option->defchoice) == NULL &&
+               strcmp(option->defchoice, "Unknown"))
            {
              if (verbose >= 0)
              {
@@ -459,16 +458,16 @@ main(int  argc,                           /* I - Number of command-line args */
                  _cupsLangPuts(stdout, _(" FAIL\n"));
 
                _cupsLangPrintf(stdout,
-                               _("      **FAIL**  BAD Default%s %s\n"
+                               _("      **FAIL**  BAD Default%s %s\n"
                                  "                REF: Page 40, section 4.5.\n"),
                                option->keyword, option->defchoice);
-              }
+             }
 
              errors ++;
            }
            else if (verbose > 0)
              _cupsLangPrintf(stdout,
-                             _("        PASS    Default%s\n"),
+                             _("        PASS    Default%s\n"),
                              option->keyword);
          }
          else
@@ -479,10 +478,10 @@ main(int  argc,                           /* I - Number of command-line args */
                _cupsLangPuts(stdout, _(" FAIL\n"));
 
              _cupsLangPrintf(stdout,
-                             _("      **FAIL**  REQUIRED Default%s\n"
-                               "                REF: Page 40, section 4.5.\n"),
-                             option->keyword);
-            }
+                             _("      **FAIL**  REQUIRED Default%s\n"
+                               "                REF: Page 40, section 4.5.\n"),
+                             option->keyword);
+           }
 
            errors ++;
          }
@@ -586,6 +585,22 @@ main(int  argc,                            /* I - Number of command-line args */
 
          errors ++;
        }
+        else if (!strncasecmp(ppd->manufacturer, "OkiData", 7) ||
+                !strncasecmp(ppd->manufacturer, "Oki Data", 8))
+       {
+         if (verbose >= 0)
+         {
+           if (!errors && !verbose)
+             _cupsLangPuts(stdout, _(" FAIL\n"));
+
+           _cupsLangPuts(stdout,
+                         _("      **FAIL**  BAD Manufacturer (should be "
+                           "\"Oki\")\n"
+                           "                REF: Page 211, table D.1.\n"));
+          }
+
+         errors ++;
+       }
        else if (verbose > 0)
          _cupsLangPuts(stdout, _("        PASS    Manufacturer\n"));
       }
@@ -1023,533 +1038,189 @@ main(int  argc,                               /* I - Number of command-line args */
          }
       }
 
-      if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) != NULL &&
-          attr->value)
+      if ((attr = ppdFindAttr(ppd, "1284DeviceID", NULL)) &&
+          strcmp(attr->name, "1284DeviceID"))
       {
-       /*
-        * This file contains localizations, check them...
-       */
+       if (verbose >= 0)
+       {
+         if (!errors && !verbose)
+           _cupsLangPuts(stdout, _(" FAIL\n"));
 
-        char           *languages,     /* Copy of attribute value */
-                       *langstart,     /* Start of current language */
-                       *langptr,       /* Pointer into languages */
-                       keyword[PPD_MAX_NAME],
-                                       /* Localization keyword */
-                       ckeyword[PPD_MAX_NAME];
-                                       /* Custom option keyword */
-       ppd_coption_t   *coption;       /* Custom option */
-       ppd_cparam_t    *cparam;        /* Custom parameter */
-        cups_array_t   *langlist;      /* List of languages so far */
-        char           ll[3];          /* Base language */
+         _cupsLangPrintf(stdout,
+                         _("      **FAIL**  %s must be 1284DeviceID!\n"
+                           "                REF: Page 72, section 5.5\n"),
+                         attr->name);
+        }
 
+       errors ++;
+      }
 
-        languages = strdup(attr->value);
-       langlist  = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+      if (!(warn & WARN_CONSTRAINTS))
+        errors = check_constraints(ppd, errors, verbose, 0);
 
-       for (langptr = languages; *langptr;)
-       {
-        /*
-         * Skip leading whitespace...
-         */
+      if (!(warn & WARN_FILTERS))
+        errors = check_filters(ppd, root, errors, verbose, 0);
 
-         while (isspace(*langptr & 255))
-           langptr ++;
+      if (!(warn & WARN_TRANSLATIONS))
+        errors = check_translations(ppd, errors, verbose, 0);
 
-         if (!*langptr)
-           break;
+      if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) != NULL &&
+         attr->value)
+      {
+       /*
+       * This file contains localizations, check for conformance of the
+       * base translation...
+       */
 
-         /*
-         * Find the end of this language name...
-         */
+        if ((attr = ppdFindAttr(ppd, "LanguageEncoding", NULL)) != NULL)
+       {
+         if (!attr->value || strcmp(attr->value, "ISOLatin1"))
+         {
+           if (!errors && !verbose)
+             _cupsLangPuts(stdout, _(" FAIL\n"));
 
-         for (langstart = langptr;
-              *langptr && !isspace(*langptr & 255);
-              langptr ++);
+            if (verbose >= 0)
+             _cupsLangPrintf(stderr,
+                             _("      **FAIL**  Bad LanguageEncoding %s - "
+                               "must be ISOLatin1!\n"),
+                             attr->value ? attr->value : "(null)");
 
-          if (*langptr)
-           *langptr++ = '\0';
+            errors ++;
+         }
 
-          j = strlen(langstart);
-         if (j != 2 && j != 5)
+          if (!ppd->lang_version || strcmp(ppd->lang_version, "English"))
          {
-           if (verbose >= 0)
-           {
-             if (!errors && !verbose)
-               _cupsLangPuts(stdout, _(" FAIL\n"));
+           if (!errors && !verbose)
+             _cupsLangPuts(stdout, _(" FAIL\n"));
 
-             _cupsLangPrintf(stdout,
-                             _("      **FAIL**  Bad language \"%s\"!\n"),
-                             langstart);
-            }
+            if (verbose >= 0)
+             _cupsLangPrintf(stderr,
+                             _("      **FAIL**  Bad LanguageVersion %s - "
+                               "must be English!\n"),
+                             ppd->lang_version ? ppd->lang_version : "(null)");
 
-           errors ++;
-           continue;
+            errors ++;
          }
-
-          cupsArrayAdd(langlist, langstart);
-
-         /*
+         
+        /*
          * Loop through all options and choices...
          */
 
-          for (option = ppdFirstOption(ppd);
+         for (option = ppdFirstOption(ppd);
               option;
               option = ppdNextOption(ppd))
          {
-           snprintf(keyword, sizeof(keyword), "%s.Translation", langstart);
-           if ((attr = ppdFindAttr(ppd, keyword, option->keyword)) == NULL)
-           {
-             if (verbose >= 0)
-             {
-               if (!errors && !verbose)
-                 _cupsLangPuts(stdout, _(" FAIL\n"));
+          /*
+           * Check for special characters outside A0 to BF, F7, or F8
+           * that are used for languages other than English.
+           */
 
-               _cupsLangPrintf(stdout,
-                               _("      **FAIL**  Missing \"%s\" translation "
-                                 "string for option %s!\n"),
-                               langstart, option->keyword);
-              }
+           for (ptr = option->text; *ptr; ptr ++)
+             if ((*ptr & 0x80) && (*ptr & 0xe0) != 0xa0 &&
+                 (*ptr & 0xff) != 0xf7 && (*ptr & 0xff) != 0xf8)
+               break;
 
-             errors ++;
-           }
-           else if (!valid_utf8(attr->text))
+           if (*ptr)
            {
-             if (verbose >= 0)
-             {
-               if (!errors && !verbose)
-                 _cupsLangPuts(stdout, _(" FAIL\n"));
-
-               _cupsLangPrintf(stdout,
-                               _("      **FAIL**  Bad UTF-8 \"%s\" translation "
-                                 "string for option %s!\n"),
-                               langstart, option->keyword);
-              }
-
-             errors ++;
-           }
-
-            for (ptr = option->text; *ptr; ptr ++)
-             if (*ptr & 128)
-               break;
+             if (!errors && !verbose)
+               _cupsLangPuts(stdout, _(" FAIL\n"));
 
-            if (*ptr)
-           {
              if (verbose >= 0)
-             {
-               if (!errors && !verbose)
-                 _cupsLangPuts(stdout, _(" FAIL\n"));
-
                _cupsLangPrintf(stdout,
-                               _("      **FAIL**  Default translation "
+                               _("      **FAIL**  Default translation "
                                  "string for option %s contains 8-bit "
                                  "characters!\n"),
                                option->keyword);
-              }
 
              errors ++;
            }
 
-           snprintf(keyword, sizeof(keyword), "%s.%s", langstart,
-                    option->keyword);
-            for (j = 0; j < option->num_choices; j ++)
+           for (j = 0; j < option->num_choices; j ++)
            {
-             if (!strcasecmp(option->choices[j].choice, "Custom") &&
-                 (coption = ppdFindCustomOption(ppd,
-                                                option->keyword)) != NULL)
-             {
-               snprintf(ckeyword, sizeof(ckeyword), "%s.Custom%s",
-                        langstart, option->keyword);
-
-               if ((attr = ppdFindAttr(ppd, ckeyword, "True")) != NULL &&
-                   !valid_utf8(attr->text))
-               {
-                 if (verbose >= 0)
-                 {
-                   if (!errors && !verbose)
-                     _cupsLangPuts(stdout, _(" FAIL\n"));
-
-                   _cupsLangPrintf(stdout,
-                                   _("      **FAIL**  Bad UTF-8 \"%s\" "
-                                     "translation string for option %s, "
-                                     "choice %s!\n"),
-                                   langstart, ckeyword + 1 + strlen(langstart),
-                                   "True");
-                 }
-
-                 errors ++;
-               }
+            /*
+             * Check for special characters outside A0 to BF, F7, or F8
+             * that are used for languages other than English.
+             */
 
-                if (strcasecmp(option->keyword, "PageSize"))
-               {
-                 for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
-                      cparam;
-                      cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
-                 {
-                   snprintf(ckeyword, sizeof(ckeyword), "%s.ParamCustom%s",
-                            langstart, option->keyword);
-                   if ((attr = ppdFindAttr(ppd, ckeyword, cparam->name)) == NULL)
-                   {
-                     if (verbose >= 0)
-                     {
-                       if (!errors && !verbose)
-                         _cupsLangPuts(stdout, _(" FAIL\n"));
-
-                       _cupsLangPrintf(stdout,
-                                       _("      **FAIL**  Missing \"%s\" "
-                                         "translation string for option %s, "
-                                         "choice %s!\n"),
-                                       langstart,
-                                       ckeyword + 1 + strlen(langstart),
-                                       cparam->name);
-                     }
-
-                     errors ++;
-                   }
-                   else if (!valid_utf8(attr->text))
-                   {
-                     if (verbose >= 0)
-                     {
-                       if (!errors && !verbose)
-                         _cupsLangPuts(stdout, _(" FAIL\n"));
-
-                       _cupsLangPrintf(stdout,
-                                       _("      **FAIL**  Bad UTF-8 \"%s\" "
-                                         "translation string for option %s, "
-                                         "choice %s!\n"),
-                                       langstart,
-                                       ckeyword + 1 + strlen(langstart),
-                                       cparam->name);
-                     }
-
-                     errors ++;
-                   }
-                  }
-                }
-             }
-             else if ((attr = ppdFindAttr(ppd, keyword, option->choices[j].choice)) == NULL)
-             {
-               if (verbose >= 0)
-               {
-                 if (!errors && !verbose)
-                   _cupsLangPuts(stdout, _(" FAIL\n"));
-
-                 _cupsLangPrintf(stdout,
-                                 _("      **FAIL**  Missing \"%s\" "
-                                   "translation string for option %s, "
-                                   "choice %s!\n"),
-                                 langstart, option->keyword,
-                                 option->choices[j].choice);
-               }
+             for (ptr = option->choices[j].text; *ptr; ptr ++)
+               if ((*ptr & 0x80) && (*ptr & 0xe0) != 0xa0 &&
+                   (*ptr & 0xff) != 0xf7 && (*ptr & 0xff) != 0xf8)
+                 break;
 
-               errors ++;
-             }
-             else if (!valid_utf8(attr->text))
+             if (*ptr)
              {
-               if (verbose >= 0)
-               {
-                 if (!errors && !verbose)
-                   _cupsLangPuts(stdout, _(" FAIL\n"));
-
-                 _cupsLangPrintf(stdout,
-                                 _("      **FAIL**  Bad UTF-8 \"%s\" "
-                                   "translation string for option %s, "
-                                   "choice %s!\n"),
-                                 langstart, option->keyword,
-                                 option->choices[j].choice);
-               }
-
-               errors ++;
-             }
-
-              for (ptr = option->choices[j].text; *ptr; ptr ++)
-               if (*ptr & 128)
-                 break;
+               if (!errors && !verbose)
+                 _cupsLangPuts(stdout, _(" FAIL\n"));
 
-              if (*ptr)
-             {
                if (verbose >= 0)
-               {
-                 if (!errors && !verbose)
-                   _cupsLangPuts(stdout, _(" FAIL\n"));
-
                  _cupsLangPrintf(stdout,
-                                 _("      **FAIL**  Default translation "
+                                 _("      **FAIL**  Default translation "
                                    "string for option %s choice %s contains "
                                    "8-bit characters!\n"),
                                  option->keyword,
                                  option->choices[j].choice);
-               }
 
                errors ++;
              }
-            }
+           }
          }
-        }
-
-       /*
-        * Verify that we have the base language for each localized one...
-       */
+       }
+      }
 
-        for (langptr = (char *)cupsArrayFirst(langlist);
-            langptr;
-            langptr = (char *)cupsArrayNext(langlist))
-         if (langptr[2])
-         {
-          /*
-           * Lookup the base language...
-           */
+     /*
+      * Final pass/fail notification...
+      */
 
-           cupsArraySave(langlist);
+      if (errors)
+       status = ERROR_CONFORMANCE;
+      else if (!verbose)
+       _cupsLangPuts(stdout, _(" PASS\n"));
 
-           strlcpy(ll, langptr, sizeof(ll));
+      if (verbose >= 0)
+      {
+        check_basics(argv[i]);
 
-           if (!cupsArrayFind(langlist, ll))
-           {
-             if (verbose >= 0)
-             {
-               if (!errors && !verbose)
-                 _cupsLangPuts(stdout, _(" FAIL\n"));
+       if (warn & WARN_CONSTRAINTS)
+         errors = check_constraints(ppd, errors, verbose, 1);
 
-               _cupsLangPrintf(stdout,
-                               _("      **FAIL**  No base translation \"%s\" "
-                                 "is included in file!\n"), ll);
-             }
+       if (warn & WARN_DEFAULTS)
+         errors = check_defaults(ppd, errors, verbose, 1);
 
-             errors ++;
-           }
+       if (warn & WARN_FILTERS)
+         errors = check_filters(ppd, root, errors, verbose, 1);
 
-           cupsArrayRestore(langlist);
-         }
+       if (warn & WARN_TRANSLATIONS)
+         errors = check_translations(ppd, errors, verbose, 1);
 
        /*
-        * Free memory used for the languages...
+       * Look for default keywords with no corresponding option...
        */
 
-        cupsArrayDelete(langlist);
-       free(languages);
-      }
-
-      for (attr = ppdFindAttr(ppd, "cupsFilter", NULL);
-           attr;
-          attr = ppdFindNextAttr(ppd, "cupsFilter", NULL))
-      {
-        if (!attr->value ||
-           sscanf(attr->value, "%15[^/]/%255s%d%255s", super, type, &cost,
-                  program) != 4)
-        {
-         if (verbose >= 0)
-         {
-           if (!errors && !verbose)
-             _cupsLangPuts(stdout, _(" FAIL\n"));
+       for (j = 0; j < ppd->num_attrs; j ++)
+       {
+         attr = ppd->attrs[j];
 
-           _cupsLangPrintf(stdout,
-                           _("      **FAIL**  Bad cupsFilter value \"%s\"!\n"),
-                           attr->value ? attr->value : "");
-          }
+          if (!strcmp(attr->name, "DefaultColorSpace") ||
+             !strcmp(attr->name, "DefaultColorSep") ||
+             !strcmp(attr->name, "DefaultFont") ||
+             !strcmp(attr->name, "DefaultImageableArea") ||
+             !strcmp(attr->name, "DefaultOutputOrder") ||
+             !strcmp(attr->name, "DefaultPaperDimension") ||
+             !strcmp(attr->name, "DefaultScreenProc") ||
+             !strcmp(attr->name, "DefaultTransfer"))
+           continue;
 
-         errors ++;
+         if (!strncmp(attr->name, "Default", 7) && 
+             !ppdFindOption(ppd, attr->name + 7))
+            _cupsLangPrintf(stdout,
+                           _("        WARN    %s has no corresponding "
+                             "options!\n"),
+                           attr->name);
        }
-       else
-       {
-         if (program[0] == '/')
-           snprintf(pathprog, sizeof(pathprog), "%s%s", root, program);
-         else
-         {
-           if ((ptr = getenv("CUPS_SERVERBIN")) == NULL)
-             ptr = CUPS_SERVERBIN;
 
-            if (*ptr == '/' || !*root)
-             snprintf(pathprog, sizeof(pathprog), "%s%s/filter/%s", root, ptr,
-                      program);
-            else
-             snprintf(pathprog, sizeof(pathprog), "%s/%s/filter/%s", root, ptr,
-                      program);
-          }
-
-         if (stat(pathprog, &statbuf))
-         {
-           if (verbose >= 0)
-           {
-             if (!errors && !verbose)
-               _cupsLangPuts(stdout, _(" FAIL\n"));
-
-             _cupsLangPrintf(stdout, _("      **FAIL**  Missing cupsFilter "
-                                       "file \"%s\"\n"), program);
-           }
-
-           errors ++;
-         }
-       }
-      }
-
-      for (attr = ppdFindAttr(ppd, "cupsPreFilter", NULL);
-           attr;
-          attr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL))
-      {
-        if (!attr->value ||
-           sscanf(attr->value, "%15[^/]/%255s%d%255s", super, type, &cost,
-                  program) != 4)
-        {
-         if (verbose >= 0)
-         {
-           if (!errors && !verbose)
-             _cupsLangPuts(stdout, _(" FAIL\n"));
-
-           _cupsLangPrintf(stdout,
-                           _("      **FAIL**  Bad cupsPreFilter value \"%s\"!\n"),
-                           attr->value ? attr->value : "");
-          }
-
-         errors ++;
-       }
-       else
-       {
-         if (program[0] == '/')
-           snprintf(pathprog, sizeof(pathprog), "%s%s", root, program);
-         else
-         {
-           if ((ptr = getenv("CUPS_SERVERBIN")) == NULL)
-             ptr = CUPS_SERVERBIN;
-
-            if (*ptr == '/' || !*root)
-             snprintf(pathprog, sizeof(pathprog), "%s%s/filter/%s", root, ptr,
-                      program);
-            else
-             snprintf(pathprog, sizeof(pathprog), "%s/%s/filter/%s", root, ptr,
-                      program);
-          }
-
-         if (stat(pathprog, &statbuf))
-         {
-           if (verbose >= 0)
-           {
-             if (!errors && !verbose)
-               _cupsLangPuts(stdout, _(" FAIL\n"));
-
-             _cupsLangPrintf(stdout, _("      **FAIL**  Missing cupsPreFilter "
-                                       "file \"%s\"\n"), program);
-           }
-
-           errors ++;
-         }
-       }
-      }
-
-      if ((attr = ppdFindAttr(ppd, "1284DeviceID", NULL)) &&
-          strcmp(attr->name, "1284DeviceID"))
-      {
-       if (verbose >= 0)
-       {
-         if (!errors && !verbose)
-           _cupsLangPuts(stdout, _(" FAIL\n"));
-
-         _cupsLangPrintf(stdout,
-                         _("      **FAIL**  %s must be 1284DeviceID!\n"
-                           "                REF: Page 72, section 5.5\n"),
-                         attr->name);
-        }
-
-       errors ++;
-      }
-
-     /*
-      * Check for bad UIConstraints...
-      */
-
-      for (j = ppd->num_consts, c = ppd->consts; j > 0; j --, c ++)
-      {
-       option  = ppdFindOption(ppd, c->option1);
-       option2 = ppdFindOption(ppd, c->option2);
-
-       if (!option || !option2)
-       {
-         if (!errors && !verbose)
-           _cupsLangPuts(stdout, _(" FAIL\n"));
-
-          if (!option)
-           _cupsLangPrintf(stdout,
-                           _("      **FAIL**  Missing option %s in "
-                             "UIConstraint \"*%s %s *%s %s\"!\n"),
-                           c->option1,
-                           c->option1, c->choice1, c->option2, c->choice2);
-         
-          if (!option2)
-           _cupsLangPrintf(stdout,
-                           _("      **FAIL**  Missing option %s in "
-                             "UIConstraint \"*%s %s *%s %s\"!\n"),
-                           c->option2,
-                           c->option1, c->choice1, c->option2, c->choice2);
-
-          continue;
-       }
-
-       if (c->choice1[0] && !ppdFindChoice(option, c->choice1))
-       {
-         if (!errors && !verbose)
-           _cupsLangPuts(stdout, _(" FAIL\n"));
-
-         _cupsLangPrintf(stdout,
-                         _("      **FAIL**  Missing choice *%s %s in "
-                           "UIConstraint \"*%s %s *%s %s\"!\n"),
-                         c->option1, c->choice1,
-                         c->option1, c->choice1, c->option2, c->choice2);
-       }
-
-       if (c->choice2[0] && !ppdFindChoice(option2, c->choice2))
-       {
-         if (!errors && !verbose)
-           _cupsLangPuts(stdout, _(" FAIL\n"));
-
-         _cupsLangPrintf(stdout,
-                         _("      **FAIL**  Missing choice *%s %s in "
-                           "UIConstraint \"*%s %s *%s %s\"!\n"),
-                         c->option2, c->choice2,
-                         c->option1, c->choice1, c->option2, c->choice2);
-       }
-      }
-
-     /*
-      * Final pass/fail notification...
-      */
-
-      if (errors)
-       status = ERROR_CONFORMANCE;
-      else if (!verbose)
-       _cupsLangPuts(stdout, _(" PASS\n"));
-        
-      if (verbose >= 0)
-      {
-        check_basics(argv[i]);
-
-       /*
-       * Look for default keywords with no corresponding option...
-       */
-
-       for (j = 0; j < ppd->num_attrs; j ++)
-       {
-         attr = ppd->attrs[j];
-
-          if (!strcmp(attr->name, "DefaultColorSpace") ||
-             !strcmp(attr->name, "DefaultColorSep") ||
-             !strcmp(attr->name, "DefaultFont") ||
-             !strcmp(attr->name, "DefaultImageableArea") ||
-             !strcmp(attr->name, "DefaultOutputOrder") ||
-             !strcmp(attr->name, "DefaultPaperDimension") ||
-             !strcmp(attr->name, "DefaultScreenProc") ||
-             !strcmp(attr->name, "DefaultTransfer"))
-           continue;
-
-         if (!strncmp(attr->name, "Default", 7) && 
-             !ppdFindOption(ppd, attr->name + 7))
-            _cupsLangPrintf(stdout,
-                           _("        WARN    %s has no corresponding "
-                             "options!\n"),
-                           attr->name);
-       }
-
-       /*
-        * Check for old Duplex option names...
-       */
+       /*
+        * Check for old Duplex option names...
+       */
 
        if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL)
           option = ppdFindOption(ppd, "KD03Duplex");
@@ -1999,6 +1670,579 @@ check_basics(const char *filename)      /* I - PPD file to check */
 }
 
 
+/*
+ * 'check_constraints()' - Check UIConstraints in the PPD file.
+ */
+
+int                                    /* O - Errors found */
+check_constraints(ppd_file_t *ppd,     /* I - PPD file */
+                  int        errors,   /* I - Errors found */
+                  int        verbose,  /* I - Verbosity level */
+                  int        warn)     /* I - Warnings only? */
+{
+  int          j;                      /* Looping var */
+  ppd_const_t  *c;                     /* Current constraint */
+  ppd_option_t *option;                /* Standard UI option */
+  ppd_option_t *option2;               /* Standard UI option */
+  const char   *prefix;                /* WARN/FAIL prefix */
+
+
+  prefix = warn ? "  WARN  " : "**FAIL**";
+
+  for (j = ppd->num_consts, c = ppd->consts; j > 0; j --, c ++)
+  {
+    option  = ppdFindOption(ppd, c->option1);
+    option2 = ppdFindOption(ppd, c->option2);
+
+    if (!option || !option2)
+    {
+      if (!warn && !errors && !verbose)
+       _cupsLangPuts(stdout, _(" FAIL\n"));
+
+      if (!option)
+       _cupsLangPrintf(stdout,
+                       _("      %s  Missing option %s in "
+                         "UIConstraint \"*%s %s *%s %s\"!\n"),
+                       prefix, c->option1,
+                       c->option1, c->choice1, c->option2, c->choice2);
+      
+      if (!option2)
+       _cupsLangPrintf(stdout,
+                       _("      %s  Missing option %s in "
+                         "UIConstraint \"*%s %s *%s %s\"!\n"),
+                       prefix, c->option2,
+                       c->option1, c->choice1, c->option2, c->choice2);
+
+      if (!warn)
+        errors ++;
+
+      continue;
+    }
+
+    if (c->choice1[0] && !ppdFindChoice(option, c->choice1))
+    {
+      if (!warn && !errors && !verbose)
+       _cupsLangPuts(stdout, _(" FAIL\n"));
+
+      _cupsLangPrintf(stdout,
+                     _("      %s  Missing choice *%s %s in "
+                       "UIConstraint \"*%s %s *%s %s\"!\n"),
+                     prefix, c->option1, c->choice1,
+                     c->option1, c->choice1, c->option2, c->choice2);
+
+      if (!warn)
+        errors ++;
+    }
+
+    if (c->choice2[0] && !ppdFindChoice(option2, c->choice2))
+    {
+      if (!warn && !errors && !verbose)
+       _cupsLangPuts(stdout, _(" FAIL\n"));
+
+      _cupsLangPrintf(stdout,
+                     _("      %s  Missing choice *%s %s in "
+                       "UIConstraint \"*%s %s *%s %s\"!\n"),
+                     prefix, c->option2, c->choice2,
+                     c->option1, c->choice1, c->option2, c->choice2);
+
+      if (!warn)
+        errors ++;
+    }
+  }
+
+  return (errors);
+}
+
+
+/*
+ * 'check_defaults()' - Check default option keywords in the PPD file.
+ */
+
+int                                    /* O - Errors found */
+check_defaults(ppd_file_t *ppd,                /* I - PPD file */
+              int        errors,       /* I - Errors found */
+              int        verbose,      /* I - Verbosity level */
+              int        warn)         /* I - Warnings only? */
+{
+  int          j, k;                   /* Looping vars */
+  ppd_attr_t   *attr;                  /* PPD attribute */
+  ppd_option_t *option;                /* Standard UI option */
+  const char   *prefix;                /* WARN/FAIL prefix */
+
+
+  prefix = warn ? "  WARN  " : "**FAIL**";
+
+  for (j = 0; j < ppd->num_attrs; j ++)
+  {
+    attr = ppd->attrs[j];
+
+    if (!strcmp(attr->name, "DefaultColorSpace") ||
+       !strcmp(attr->name, "DefaultFont") ||
+       !strcmp(attr->name, "DefaultImageableArea") ||
+       !strcmp(attr->name, "DefaultOutputOrder") ||
+       !strcmp(attr->name, "DefaultPaperDimension") ||
+       !strcmp(attr->name, "DefaultResolution") ||
+       !strcmp(attr->name, "DefaultTransfer"))
+      continue;
+
+    if (!strncmp(attr->name, "Default", 7))
+    {
+      if ((option = ppdFindOption(ppd, attr->name + 7)) != NULL &&
+         strcmp(attr->value, "Unknown"))
+      {
+       /*
+       * Check that the default option value matches a choice...
+       */
+
+       for (k = 0; k < option->num_choices; k ++)
+         if (!strcmp(option->choices[k].choice, attr->value))
+           break;
+
+       if (k >= option->num_choices)
+       {
+         if (!warn && !errors && !verbose)
+           _cupsLangPuts(stdout, _(" FAIL\n"));
+
+         if (verbose >= 0)
+           _cupsLangPrintf(stdout,
+                           _("      %s  %s %s does not exist!\n"),
+                           prefix, attr->name, attr->value);
+
+          if (!warn)
+           errors ++;
+       }
+      }
+    }
+  }
+
+  return (errors);
+}
+
+
+/*
+ * 'check_filters()' - Check filters in the PPD file.
+ */
+
+int                                    /* O - Errors found */
+check_filters(ppd_file_t *ppd,         /* I - PPD file */
+              const char *root,                /* I - Root directory */
+             int        errors,        /* I - Errors found */
+             int        verbose,       /* I - Verbosity level */
+             int        warn)          /* I - Warnings only? */
+{
+  ppd_attr_t   *attr;                  /* PPD attribute */
+  const char   *ptr;                   /* Pointer into string */
+  struct stat  statbuf;                /* File information */
+  char         super[16],              /* Super-type for filter */
+               type[256],              /* Type for filter */
+               program[256],           /* Program/filter name */
+               pathprog[1024];         /* Complete path to program/filter */
+  int          cost;                   /* Cost of filter */
+  const char   *prefix;                /* WARN/FAIL prefix */
+
+
+  prefix = warn ? "  WARN  " : "**FAIL**";
+
+  for (attr = ppdFindAttr(ppd, "cupsFilter", NULL);
+       attr;
+       attr = ppdFindNextAttr(ppd, "cupsFilter", NULL))
+  {
+    if (!attr->value ||
+       sscanf(attr->value, "%15[^/]/%255s%d%255s", super, type, &cost,
+              program) != 4)
+    {
+      if (!warn && !errors && !verbose)
+       _cupsLangPuts(stdout, _(" FAIL\n"));
+
+      if (verbose >= 0)
+       _cupsLangPrintf(stdout,
+                       _("      %s  Bad cupsFilter value \"%s\"!\n"),
+                       prefix, attr->value ? attr->value : "");
+
+      if (!warn)
+        errors ++;
+    }
+    else
+    {
+      if (program[0] == '/')
+       snprintf(pathprog, sizeof(pathprog), "%s%s", root, program);
+      else
+      {
+       if ((ptr = getenv("CUPS_SERVERBIN")) == NULL)
+         ptr = CUPS_SERVERBIN;
+
+       if (*ptr == '/' || !*root)
+         snprintf(pathprog, sizeof(pathprog), "%s%s/filter/%s", root, ptr,
+                  program);
+       else
+         snprintf(pathprog, sizeof(pathprog), "%s/%s/filter/%s", root, ptr,
+                  program);
+      }
+
+      if (stat(pathprog, &statbuf))
+      {
+       if (!warn && !errors && !verbose)
+         _cupsLangPuts(stdout, _(" FAIL\n"));
+
+       if (verbose >= 0)
+         _cupsLangPrintf(stdout, _("      %s  Missing cupsFilter "
+                                   "file \"%s\"\n"), prefix, program);
+
+       if (!warn)
+         errors ++;
+      }
+    }
+  }
+
+  for (attr = ppdFindAttr(ppd, "cupsPreFilter", NULL);
+       attr;
+       attr = ppdFindNextAttr(ppd, "cupsPreFilter", NULL))
+  {
+    if (!attr->value ||
+       sscanf(attr->value, "%15[^/]/%255s%d%255s", super, type, &cost,
+              program) != 4)
+    {
+      if (!warn && !errors && !verbose)
+       _cupsLangPuts(stdout, _(" FAIL\n"));
+
+      if (verbose >= 0)
+       _cupsLangPrintf(stdout,
+                       _("      %s  Bad cupsPreFilter value \"%s\"!\n"),
+                       prefix, attr->value ? attr->value : "");
+
+      if (!warn)
+        errors ++;
+    }
+    else
+    {
+      if (program[0] == '/')
+       snprintf(pathprog, sizeof(pathprog), "%s%s", root, program);
+      else
+      {
+       if ((ptr = getenv("CUPS_SERVERBIN")) == NULL)
+         ptr = CUPS_SERVERBIN;
+
+       if (*ptr == '/' || !*root)
+         snprintf(pathprog, sizeof(pathprog), "%s%s/filter/%s", root, ptr,
+                  program);
+       else
+         snprintf(pathprog, sizeof(pathprog), "%s/%s/filter/%s", root, ptr,
+                  program);
+      }
+
+      if (stat(pathprog, &statbuf))
+      {
+       if (!warn && !errors && !verbose)
+         _cupsLangPuts(stdout, _(" FAIL\n"));
+
+       if (verbose >= 0)
+         _cupsLangPrintf(stdout, _("      %s  Missing cupsPreFilter "
+                                   "file \"%s\"\n"), prefix, program);
+
+        if (!warn)
+         errors ++;
+      }
+    }
+  }
+
+  return (errors);
+}
+
+
+/*
+ * 'check_translations()' - Check translations in the PPD file.
+ */
+
+int                                    /* O - Errors found */
+check_translations(ppd_file_t *ppd,    /* I - PPD file */
+                   int        errors,  /* I - Errors found */
+                   int        verbose, /* I - Verbosity level */
+                   int        warn)    /* I - Warnings only? */
+{
+  int          j;                      /* Looping var */
+  ppd_attr_t   *attr;                  /* PPD attribute */
+  char         *languages,             /* Copy of attribute value */
+               *langstart,             /* Start of current language */
+               *langptr,               /* Pointer into languages */
+               keyword[PPD_MAX_NAME],  /* Localization keyword (full) */
+               llkeyword[PPD_MAX_NAME],/* Localization keyword (base) */
+               ckeyword[PPD_MAX_NAME], /* Custom option keyword (full) */
+               cllkeyword[PPD_MAX_NAME];
+                                       /* Custom option keyword (base) */
+  ppd_option_t *option;                /* Standard UI option */
+  ppd_coption_t        *coption;               /* Custom option */
+  ppd_cparam_t *cparam;                /* Custom parameter */
+  cups_array_t *langlist;              /* List of languages so far */
+  char         ll[3];                  /* Base language */
+  const char   *prefix;                /* WARN/FAIL prefix */
+
+
+  prefix = warn ? "  WARN  " : "**FAIL**";
+
+  if ((attr = ppdFindAttr(ppd, "cupsLanguages", NULL)) != NULL &&
+      attr->value)
+  {
+   /*
+    * This file contains localizations, check them...
+    */
+
+    languages = strdup(attr->value);
+    langlist  = cupsArrayNew((cups_array_func_t)strcmp, NULL);
+
+    for (langptr = languages; *langptr;)
+    {
+     /*
+      * Skip leading whitespace...
+      */
+
+      while (isspace(*langptr & 255))
+       langptr ++;
+
+      if (!*langptr)
+       break;
+
+     /*
+      * Find the end of this language name...
+      */
+
+      for (langstart = langptr;
+          *langptr && !isspace(*langptr & 255);
+          langptr ++);
+
+      if (*langptr)
+       *langptr++ = '\0';
+
+      j = strlen(langstart);
+      if (j != 2 && j != 5)
+      {
+       if (!warn && !errors && !verbose)
+         _cupsLangPuts(stdout, _(" FAIL\n"));
+
+       if (verbose >= 0)
+         _cupsLangPrintf(stdout,
+                         _("      %s  Bad language \"%s\"!\n"),
+                         prefix, langstart);
+
+       if (!warn)
+         errors ++;
+
+       continue;
+      }
+
+      cupsArrayAdd(langlist, langstart);
+
+      strlcpy(ll, langstart, sizeof(ll));
+
+     /*
+      * Loop through all options and choices...
+      */
+
+      for (option = ppdFirstOption(ppd);
+          option;
+          option = ppdNextOption(ppd))
+      {
+       snprintf(keyword, sizeof(keyword), "%s.Translation", langstart);
+       snprintf(llkeyword, sizeof(llkeyword), "%s.Translation", ll);
+
+       if ((attr = ppdFindAttr(ppd, keyword, option->keyword)) == NULL &&
+           (attr = ppdFindAttr(ppd, llkeyword, option->keyword)) == NULL)
+       {
+         if (!warn && !errors && !verbose)
+           _cupsLangPuts(stdout, _(" FAIL\n"));
+
+         if (verbose >= 0)
+           _cupsLangPrintf(stdout,
+                           _("      %s  Missing \"%s\" translation "
+                             "string for option %s!\n"),
+                           prefix, langstart, option->keyword);
+
+          if (!warn)
+           errors ++;
+       }
+       else if (!valid_utf8(attr->text))
+       {
+         if (!warn && !errors && !verbose)
+           _cupsLangPuts(stdout, _(" FAIL\n"));
+
+         if (verbose >= 0)
+           _cupsLangPrintf(stdout,
+                           _("      %s  Bad UTF-8 \"%s\" translation "
+                             "string for option %s!\n"),
+                           prefix, langstart, option->keyword);
+
+         if (!warn)
+           errors ++;
+       }
+
+       snprintf(keyword, sizeof(keyword), "%s.%s", langstart,
+                option->keyword);
+       snprintf(llkeyword, sizeof(llkeyword), "%s.%s", ll,
+                option->keyword);
+
+       for (j = 0; j < option->num_choices; j ++)
+       {
+         if (!strcasecmp(option->choices[j].choice, "Custom") &&
+             (coption = ppdFindCustomOption(ppd,
+                                            option->keyword)) != NULL)
+         {
+           snprintf(ckeyword, sizeof(ckeyword), "%s.Custom%s",
+                    langstart, option->keyword);
+
+           if ((attr = ppdFindAttr(ppd, ckeyword, "True")) != NULL &&
+               !valid_utf8(attr->text))
+           {
+             if (!warn && !errors && !verbose)
+               _cupsLangPuts(stdout, _(" FAIL\n"));
+
+             if (verbose >= 0)
+               _cupsLangPrintf(stdout,
+                               _("      %s  Bad UTF-8 \"%s\" "
+                                 "translation string for option %s, "
+                                 "choice %s!\n"),
+                               prefix, langstart,
+                               ckeyword + 1 + strlen(langstart),
+                               "True");
+
+              if (!warn)
+               errors ++;
+           }
+
+           if (strcasecmp(option->keyword, "PageSize"))
+           {
+             for (cparam = (ppd_cparam_t *)cupsArrayFirst(coption->params);
+                  cparam;
+                  cparam = (ppd_cparam_t *)cupsArrayNext(coption->params))
+             {
+               snprintf(ckeyword, sizeof(ckeyword), "%s.ParamCustom%s",
+                        langstart, option->keyword);
+               snprintf(cllkeyword, sizeof(cllkeyword), "%s.ParamCustom%s",
+                        ll, option->keyword);
+
+               if ((attr = ppdFindAttr(ppd, ckeyword,
+                                       cparam->name)) == NULL &&
+                   (attr = ppdFindAttr(ppd, cllkeyword,
+                                       cparam->name)) == NULL)
+               {
+                 if (!warn && !errors && !verbose)
+                   _cupsLangPuts(stdout, _(" FAIL\n"));
+
+                 if (verbose >= 0)
+                   _cupsLangPrintf(stdout,
+                                   _("      %s  Missing \"%s\" "
+                                     "translation string for option %s, "
+                                     "choice %s!\n"),
+                                   prefix, langstart,
+                                   ckeyword + 1 + strlen(langstart),
+                                   cparam->name);
+
+                  if (!warn)
+                   errors ++;
+               }
+               else if (!valid_utf8(attr->text))
+               {
+                 if (!warn && !errors && !verbose)
+                   _cupsLangPuts(stdout, _(" FAIL\n"));
+
+                 if (verbose >= 0)
+                   _cupsLangPrintf(stdout,
+                                   _("      %s  Bad UTF-8 \"%s\" "
+                                     "translation string for option %s, "
+                                     "choice %s!\n"),
+                                   prefix, langstart,
+                                   ckeyword + 1 + strlen(langstart),
+                                   cparam->name);
+
+                 if (!warn)
+                   errors ++;
+               }
+             }
+           }
+         }
+         else if ((attr = ppdFindAttr(ppd, keyword,
+                                      option->choices[j].choice)) == NULL &&
+                  (attr = ppdFindAttr(ppd, llkeyword,
+                                      option->choices[j].choice)) == NULL)
+         {
+           if (!warn && !errors && !verbose)
+             _cupsLangPuts(stdout, _(" FAIL\n"));
+
+           if (verbose >= 0)
+             _cupsLangPrintf(stdout,
+                             _("      %s  Missing \"%s\" "
+                               "translation string for option %s, "
+                               "choice %s!\n"),
+                             prefix, langstart, option->keyword,
+                             option->choices[j].choice);
+
+           if (!warn)
+             errors ++;
+         }
+         else if (!valid_utf8(attr->text))
+         {
+           if (!warn && !errors && !verbose)
+             _cupsLangPuts(stdout, _(" FAIL\n"));
+
+           if (verbose >= 0)
+             _cupsLangPrintf(stdout,
+                             _("      %s  Bad UTF-8 \"%s\" "
+                               "translation string for option %s, "
+                               "choice %s!\n"),
+                             prefix, langstart, option->keyword,
+                             option->choices[j].choice);
+
+           if (!warn)
+             errors ++;
+         }
+       }
+      }
+    }
+
+   /*
+    * Verify that we have the base language for each localized one...
+    */
+
+    for (langptr = (char *)cupsArrayFirst(langlist);
+        langptr;
+        langptr = (char *)cupsArrayNext(langlist))
+      if (langptr[2])
+      {
+       /*
+       * Lookup the base language...
+       */
+
+       cupsArraySave(langlist);
+
+       strlcpy(ll, langptr, sizeof(ll));
+
+       if (!cupsArrayFind(langlist, ll) && strcmp(ll, "zh"))
+       {
+         if (!warn && !errors && !verbose)
+           _cupsLangPuts(stdout, _(" FAIL\n"));
+
+         if (verbose >= 0)
+           _cupsLangPrintf(stdout,
+                           _("      %s  No base translation \"%s\" "
+                             "is included in file!\n"), prefix, ll);
+
+         if (!warn)
+           errors ++;
+       }
+
+       cupsArrayRestore(langlist);
+      }
+
+   /*
+    * Free memory used for the languages...
+    */
+
+    cupsArrayDelete(langlist);
+    free(languages);
+  }
+
+  return (errors);
+}
+
+
 /*
  * 'show_conflicts()' - Show option conflicts in a PPD file.
  */
@@ -2107,10 +2351,19 @@ void
 usage(void)
 {
   _cupsLangPuts(stdout,
-                _("Usage: cupstestppd [-R root-directory] [-q] [-r] [-v[v]] "
-                 "filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n"
-                 "       program | cupstestppd [-R root-directory] [-q] [-r] "
-                 "[-v[v]] -\n"));
+                _("Usage: cupstestppd [options] filename1.ppd[.gz] "
+                 "[... filenameN.ppd[.gz]]\n"
+                 "       program | cupstestppd [options] -\n"
+                 "\n"
+                 "Options:\n"
+                 "\n"
+                 "    -R root-directory    Set alternate root\n"
+                 "    -W {all,none,constraints,defaults,filters,translations}\n"
+                 "                         Issue warnings instead of errors\n"
+                 "    -q                   Run silently\n"
+                 "    -r                   Use 'relaxed' open mode\n"
+                 "    -v                   Be slightly verbose\n"
+                 "    -vv                  Be very verbose\n"));
 
   exit(ERROR_USAGE);
 }
@@ -2193,5 +2446,5 @@ valid_utf8(const char *s)         /* I - String to check */
 
 
 /*
- * End of "$Id: cupstestppd.c 6444 2007-04-04 22:13:58Z mike $".
+ * End of "$Id: cupstestppd.c 6509 2007-05-03 22:58:41Z mike $".
  */
index 24fb466bb0fb30a3bb02cc2c2d0f085abed7d637..bb9f953bc647e9c890c9fbe3286e6ec1ea74ed2d 100644 (file)
@@ -10,7 +10,7 @@
 </TD>
 <TD VALIGN="TOP"><B>Description:</B> {printer_info}<BR>
 <B>Location:</B> {printer_location}<BR>
-<B>Make and Model:</B> {printer_make_and_model}<BR>
+<B>Pritner Driver:</B> {printer_make_and_model}<BR>
 <B>Printer State:</B> {printer_state=3?idle:{printer_state=4?processing:stopped}},
 {printer_is_accepting_jobs=0?rejecting jobs:accepting jobs}, {printer_is_shared=0?not:} published.
 {?device_uri=?:<BR><B>Device URI:</B> {device_uri}}
diff --git a/test/get-ppd-printer.test b/test/get-ppd-printer.test
new file mode 100644 (file)
index 0000000..4f723f8
--- /dev/null
@@ -0,0 +1,20 @@
+# Get printer PPD file using CUPS-Get-PPD
+{
+       # The name of the test...
+       NAME "Get printer PPD file using CUPS-Get-PPD"
+
+       # The resource to use for the POST
+       # RESOURCE /admin
+
+       # The operation to use
+       OPERATION CUPS-Get-PPD
+
+       # Attributes, starting in the operation group...
+       GROUP operation
+       ATTR charset attributes-charset utf-8
+       ATTR language attributes-natural-language en
+       ATTR uri printer-uri $uri
+
+       # What statuses are OK?
+       STATUS successful-ok
+}
diff --git a/test/get-ppd.test b/test/get-ppd.test
new file mode 100644 (file)
index 0000000..24a935e
--- /dev/null
@@ -0,0 +1,20 @@
+# Get PPD file using CUPS-get-ppd
+{
+       # The name of the test...
+       NAME "Get PPD file using CUPS-get-ppd"
+
+       # The resource to use for the POST
+       # RESOURCE /admin
+
+       # The operation to use
+       OPERATION CUPS-get-ppd
+
+       # Attributes, starting in the operation group...
+       GROUP operation
+       ATTR charset attributes-charset utf-8
+       ATTR language attributes-natural-language en
+       ATTR name ppd-name $ENV[ppd-name]
+
+       # What statuses are OK?
+       STATUS successful-ok
+}
diff --git a/test/get-ppds-language.test b/test/get-ppds-language.test
new file mode 100644 (file)
index 0000000..2ed0118
--- /dev/null
@@ -0,0 +1,21 @@
+# Get PPD files using CUPS-Get-PPDs and language
+{
+       # The name of the test...
+       NAME "Get PPD files using CUPS-Get-PPDs and language"
+
+       # The resource to use for the POST
+       # RESOURCE /admin
+
+       # The operation to use
+       OPERATION CUPS-Get-PPDs
+
+       # Attributes, starting in the operation group...
+       GROUP operation
+       ATTR charset attributes-charset utf-8
+       ATTR language attributes-natural-language en
+       ATTR uri printer-uri $uri
+       ATTR language ppd-natural-language $ENV[language]
+
+       # What statuses are OK?
+       STATUS successful-ok
+}
diff --git a/test/get-ppds-make-and-model.test b/test/get-ppds-make-and-model.test
new file mode 100644 (file)
index 0000000..c57b147
--- /dev/null
@@ -0,0 +1,21 @@
+# Get PPD files using CUPS-Get-PPDs and model
+{
+       # The name of the test...
+       NAME "Get PPD files using CUPS-Get-PPDs and model"
+
+       # The resource to use for the POST
+       # RESOURCE /admin
+
+       # The operation to use
+       OPERATION CUPS-Get-PPDs
+
+       # Attributes, starting in the operation group...
+       GROUP operation
+       ATTR charset attributes-charset utf-8
+       ATTR language attributes-natural-language en
+       ATTR uri printer-uri $uri
+       ATTR text ppd-make-and-model $ENV[model]
+
+       # What statuses are OK?
+       STATUS successful-ok
+}
diff --git a/test/get-ppds-make.test b/test/get-ppds-make.test
new file mode 100644 (file)
index 0000000..ac3f736
--- /dev/null
@@ -0,0 +1,21 @@
+# Get PPD files using CUPS-Get-PPDs and make
+{
+       # The name of the test...
+       NAME "Get PPD files using CUPS-Get-PPDs and make"
+
+       # The resource to use for the POST
+       # RESOURCE /admin
+
+       # The operation to use
+       OPERATION CUPS-Get-PPDs
+
+       # Attributes, starting in the operation group...
+       GROUP operation
+       ATTR charset attributes-charset utf-8
+       ATTR language attributes-natural-language en
+       ATTR uri printer-uri $uri
+       ATTR text ppd-make $ENV[make]
+
+       # What statuses are OK?
+       STATUS successful-ok
+}
diff --git a/test/get-ppds-product.test b/test/get-ppds-product.test
new file mode 100644 (file)
index 0000000..b0535f7
--- /dev/null
@@ -0,0 +1,21 @@
+# Get PPD files using CUPS-Get-PPDs and Product
+{
+       # The name of the test...
+       NAME "Get PPD files using CUPS-Get-PPDs and Product"
+
+       # The resource to use for the POST
+       # RESOURCE /admin
+
+       # The operation to use
+       OPERATION CUPS-Get-PPDs
+
+       # Attributes, starting in the operation group...
+       GROUP operation
+       ATTR charset attributes-charset utf-8
+       ATTR language attributes-natural-language en
+       ATTR uri printer-uri $uri
+       ATTR text ppd-product $ENV[product]
+
+       # What statuses are OK?
+       STATUS successful-ok
+}
diff --git a/test/get-ppds-psversion.test b/test/get-ppds-psversion.test
new file mode 100644 (file)
index 0000000..b7f93b6
--- /dev/null
@@ -0,0 +1,21 @@
+# Get PPD files using CUPS-Get-PPDs and PSVersion
+{
+       # The name of the test...
+       NAME "Get PPD files using CUPS-Get-PPDs and PSVersion"
+
+       # The resource to use for the POST
+       # RESOURCE /admin
+
+       # The operation to use
+       OPERATION CUPS-Get-PPDs
+
+       # Attributes, starting in the operation group...
+       GROUP operation
+       ATTR charset attributes-charset utf-8
+       ATTR language attributes-natural-language en
+       ATTR uri printer-uri $uri
+       ATTR text ppd-psversion $ENV[psversion]
+
+       # What statuses are OK?
+       STATUS successful-ok
+}
index 7a127e5dfe5622fd6007fa67b8c847a934431473..708d1a69f37bb2b94324c5337c12dc060b5d705b 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * "$Id: ipptest.c 5876 2006-08-24 15:05:04Z mike $"
+ * "$Id: ipptest.c 6503 2007-05-01 23:06:44Z mike $"
  *
  *   IPP test command for the Common UNIX Printing System (CUPS).
  *
- *   Copyright 1997-2006 by Easy Software Products.
+ *   Copyright 1997-2007 by Easy Software Products.
  *
  *   These coded instructions, statements, and computer programs are the
  *   property of Easy Software Products and are protected by Federal
@@ -142,6 +142,15 @@ main(int  argc,                            /* I - Number of command-line arguments */
     {
       if (!strcmp(argv[i], "-v"))
         Verbosity ++;
+      else if (!strcmp(argv[i], "-d"))
+      {
+        i ++;
+
+       if (i >= argc)
+         usage(NULL);
+       else
+         putenv(argv[i]);
+      }
       else if (!strcmp(argv[i], "-i"))
       {
         i++;
@@ -454,9 +463,28 @@ do_tests(const char *uri,          /* I - URI to connect on */
              strlcpy(tokenptr, cupsUser(), sizeof(token) - (tokenptr - token));
              tempptr += 5;
            }
+           else if (!strncasecmp(tempptr + 1, "ENV[", 4))
+           {
+             char *end;                /* End of $ENV[name] */
+
+
+             if ((end = strchr(tempptr + 5, ']')) != NULL)
+             {
+               *end++ = '\0';
+               strlcpy(tokenptr,
+                       getenv(tempptr + 5) ? getenv(tempptr + 5) : tempptr + 5,
+                       sizeof(token) - (tokenptr - token));
+               tempptr = end;
+             }
+             else
+             {
+               *tokenptr++ = *tempptr++;
+               *tokenptr   = '\0';
+             }
+           }
             else
            {
-             *tokenptr++ = *tempptr ++;
+             *tokenptr++ = *tempptr++;
              *tokenptr   = '\0';
            }
 
@@ -593,7 +621,8 @@ do_tests(const char *uri,           /* I - URI to connect on */
     if (filename[0])
       response = cupsDoFileRequest(http, request, resource, filename);
     else
-      response = cupsDoRequest(http, request, resource);
+      response = cupsDoIORequest(http, request, resource, -1,
+                                 Verbosity ? 1 : -1);
 
     if (response == NULL)
     {
@@ -671,7 +700,7 @@ do_tests(const char *uri,           /* I - URI to connect on */
          puts("        BAD STATUS");
 
        printf("        status-code = %04x (%s)\n",
-              cupsLastError(), cupsLastErrorString());
+              cupsLastError(), ippErrorString(cupsLastError()));
 
         for (i = 0; i < num_expects; i ++)
          if (ippFindAttribute(response, expects[i], IPP_TAG_ZERO) == NULL)
@@ -924,5 +953,5 @@ usage(const char *option)           /* I - Option string or NULL */
 
 
 /*
- * End of "$Id: ipptest.c 5876 2006-08-24 15:05:04Z mike $".
+ * End of "$Id: ipptest.c 6503 2007-05-01 23:06:44Z mike $".
  */