]> git.ipfire.org Git - thirdparty/cups.git/commitdiff
Merge changes from CUPS 1.6svn-r10510.
authormsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Wed, 23 May 2012 22:51:18 +0000 (22:51 +0000)
committermsweet <msweet@a1ca3aef-8c08-0410-bb20-df032aa958be>
Wed, 23 May 2012 22:51:18 +0000 (22:51 +0000)
git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@3833 a1ca3aef-8c08-0410-bb20-df032aa958be

79 files changed:
CHANGES-1.5.txt
CHANGES.txt
INSTALL.txt
IPPTOOL.txt
Makedefs.in
Makefile
README.txt
backend/dnssd.c
backend/ipp.c
backend/snmp-supplies.c
backend/usb-libusb.c
berkeley/lpr.c
cgi-bin/makedocset.c
config-scripts/cups-common.m4
config-scripts/cups-dnssd.m4
config-scripts/cups-ssl.m4
config.h.in
cups/cups-private.h
cups/dest-job.c
cups/dest-localization.c
cups/dest-options.c
cups/dest.c
cups/http-addr.c
cups/http.c
cups/ipp.c
cups/language-private.h
cups/language.c
cups/page.c
cups/pwg-media.c
cups/pwg-private.h
cups/request.c
cups/testcups.c
cups/util.c
doc/help/api-cups.html
doc/help/api-ppd.html
doc/help/man-ipptoolfile.html
doc/help/ref-cupsd-conf.html.in
doc/help/spec-cmp.html
doc/help/spec-ppd.html
examples/ppdx.c [new file with mode: 0644]
examples/ppdx.h [new file with mode: 0644]
examples/testppdx.c [new file with mode: 0644]
examples/testppdx.ppd [new file with mode: 0644]
filter/spec-ppd.shtml
install-sh
man/cupsd.conf.man.in
man/filter.man
man/ipptoolfile.man
packaging/cups.list.in
scheduler/Makefile
scheduler/client.c
scheduler/colorman.c [new file with mode: 0644]
scheduler/colorman.h [new file with mode: 0644]
scheduler/conf.c
scheduler/conf.h
scheduler/cups-driverd.cxx
scheduler/cupsd.h
scheduler/dirsvc.c
scheduler/env.c
scheduler/ipp.c
scheduler/job.c
scheduler/job.h
scheduler/printers.c
scheduler/printers.h
scheduler/server.c
scheduler/sysman.c
scheduler/tls-darwin.c
systemv/lp.c
templates/jobs.tmpl
test/5.1-lpadmin.sh
test/5.5-lp.sh
test/5.6-lpr.sh
test/Makefile
test/ipp-1.1.test
test/ipptool.c
test/run-stp-tests.sh
test/testfile.pcl [new file with mode: 0644]
tools/testbtmm.c [new file with mode: 0644]
xcode/CUPS.xcodeproj/project.pbxproj

index c8dcb991e4403480440dca571f5cfdcbfd17d0ab..d8dda7d092f273f9f8d1306d688ccff85a356117 100644 (file)
@@ -1,8 +1,30 @@
 CHANGES-1.5.txt
 ---------------
 
+CHANGES IN CUPS V1.5.4
+
+       - Multiple libusb backend fixes (STR #4098, STR #4100)
+       - The IPP backend no longer tries to get the job status for printers
+         that do not implement the required operation (STR #4083)
+       - Sending a document in an unsupported format to an IPP printer now
+         automatically cancels the job (STR #4093)
+       - Fix some error reporting issues when printing from /dev/null and
+         other unusual situations (STR #4015)
+       - The scheduler now sets the CUPS_MAX_MESSAGE environment variable for
+         filters (STR #4074)
+       - Fixed a build issue when using older versions of autoconf (STR #4084)
+       - The IPP backend now treats the client-error-not-possible status code
+         as a job history issue, allowing IPP printing to Windows to work
+         (STR #4047)
+       - The IPP backend incorrectly included the document-format and
+         compression attributes in Create-Job requests (STR #4086)
+       - The libusb-based USB backend did not work on non-Linux platforms
+         (STR #4088)
+
+
 CHANGES IN CUPS V1.5.3
 
+       - httpReconnect() did not reset the read/write buffers (STR #4065)
        - Compiling without threading support failed (STR #4060)
        - Fixed compile problem with old versions of OpenSSL (STR #4036)
        - The network backends did not check SNMP supply levels regularly
index 33aa961dc82bed367917dd04aa6f69ceec52eec4..7fc5a426257b4443515f9ab60478e317ca873aff 100644 (file)
@@ -1,9 +1,12 @@
-CHANGES.txt - 1.6b1 - 2012-04-17
+CHANGES.txt - 1.6b1 - 2012-05-22
 --------------------------------
 
 CHANGES IN CUPS V1.6b1
 
-       - Documentation updates (STR #3927, STR #3980, STR #4010)
+       - Documentation updates (STR #3927, STR #3980, STR #4010, STR #4068)
+       - The scheduler now consolidates all PPD updates from filters at the
+         end of the job (STR #4075)
+       - CUPS now supports color management using colord (STR #3808)
        - CUPS now supports Bonjour using Avahi (STR #3066)
        - The PreserveJobFiles and PreserveJobHistory directives now support
          specification of a time interval (STR #3143)
index dc623d0758bc62af9a6d310875f038b78de007fa..0e9ebe3914ccc2b7d0ab8add8782adb34c59846c 100644 (file)
@@ -1,4 +1,4 @@
-INSTALL - CUPS v1.6.0 - 2012-04-23
+INSTALL - CUPS v1.6.0 - 2012-05-23
 ----------------------------------
 
 This file describes how to compile and install CUPS from source code. For more
index 9cd2201032ec5c8d1657147101116e3ccf70bacc..1d1fce704195f217122ff3e716db0cd79c5836b2 100644 (file)
@@ -88,6 +88,7 @@ CONFORMANCE TESTS
        onepage-letter.pdf
        onepage-letter.ps
        testfile.jpg
+       testfile.pcl
        testfile.pdf
        testfile.ps
        testfile.txt
index 9bf7afa85d4f838896c8d7d198a4cd69dfaba521..41612af7186c0d1038c576c034426e1de1fdd781 100644 (file)
@@ -24,7 +24,7 @@ CHMOD         =       @CHMOD@
 CXX            =       @LIBTOOL@ @CXX@
 DSO            =       @DSO@
 DSOXX          =       @DSOXX@
-HTMLDOC                =       @HTMLDOC@
+GZIP           =       @GZIP@
 INSTALL                =       @INSTALL@
 LD             =       @LD@
 LIBTOOL                =       @LIBTOOL@
@@ -41,8 +41,8 @@ SHELL         =       /bin/sh
 #
 
 INSTALL_BIN    =       $(LIBTOOL) $(INSTALL) -c -m 555 @INSTALL_STRIP@
-INSTALL_CONFIG =       $(INSTALL) -c -m @CUPS_CONFIG_FILE_PERM@
 INSTALL_COMPDATA =     $(INSTALL) -c -m 444 @INSTALL_GZIP@
+INSTALL_CONFIG =       $(INSTALL) -c -m @CUPS_CONFIG_FILE_PERM@
 INSTALL_DATA   =       $(INSTALL) -c -m 444
 INSTALL_DIR    =       $(INSTALL) -d
 INSTALL_LIB    =       $(LIBTOOL) $(INSTALL) -c -m 555 @INSTALL_STRIP@
index 6d61c6fba3114d45d92118965e47fec9c55166c4..ca8416dae02bcb2a46e22bb3ab1b5fb2a1461d5e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
 #
 #   Top-level Makefile for CUPS.
 #
-#   Copyright 2007-2010 by Apple Inc.
+#   Copyright 2007-2012 by Apple Inc.
 #   Copyright 1997-2007 by Easy Software Products, all rights reserved.
 #
 #   These coded instructions, statements, and computer programs are the
@@ -275,10 +275,10 @@ docset:   apihelp
                doc/help/api-*.tokens
        $(RM) doc/help/api-*.tokens
        echo Indexing docset...
-       /Developer/usr/bin/docsetutil index org.cups.docset
+       /Applications/Xcode.app/Contents/Developer/usr/bin/docsetutil index org.cups.docset
        echo Generating docset archive and feed...
        $(RM) org.cups.docset.atom
-       /Developer/usr/bin/docsetutil package --output org.cups.docset.xar \
+       /Applications/Xcode.app/Contents/Developer/usr/bin/docsetutil package --output org.cups.docset.xar \
                --atom org.cups.docset.atom \
                --download-url http://www.cups.org/org.cups.docset.xar \
                org.cups.docset
index 944fb67e74a33258285e916106634b26cea2fa71..6fe8727a4ef8febf1ffaa4ca34abde0066918aa1 100644 (file)
@@ -1,4 +1,4 @@
-README - CUPS v1.6.0 - 2012-04-23
+README - CUPS v1.6.0 - 2012-05-23
 ----------------------------------
 
 Looking for compile instructions?  Read the file "INSTALL.txt"
index 2984407df1cf1b0483862e81c2ccf8e93f7a254a..7cff1cb4f96d15b570b4828276f69b4280b0a48f 100644 (file)
@@ -331,7 +331,7 @@ main(int  argc,                             /* I - Number of command-line args */
 #ifdef HAVE_AVAHI
   if ((simple_poll = avahi_simple_poll_new()) == NULL)
   {
-    fputs("DEBUG: Unable to create avahi simple poll object.\n", stderr);
+    fputs("DEBUG: Unable to create Avahi simple poll object.\n", stderr);
     return (1);
   }
 
@@ -341,7 +341,7 @@ main(int  argc,                             /* I - Number of command-line args */
                            0, client_callback, simple_poll, &error);
   if (!client)
   {
-    fputs("DEBUG: Unable to create avahi client.\n", stderr);
+    fputs("DEBUG: Unable to create Avahi client.\n", stderr);
     return (1);
   }
 
@@ -587,10 +587,7 @@ browse_callback(
                   "interfaceIndex=%d, errorCode=%d, serviceName=\"%s\", "
                  "regtype=\"%s\", replyDomain=\"%s\", context=%p)\n",
           sdRef, flags, interfaceIndex, errorCode,
-         serviceName ? serviceName : "(null)",
-         regtype ? regtype : "(null)",
-         replyDomain ? replyDomain : "(null)",
-         context);
+         serviceName, regtype, replyDomain, context);
 
  /*
   * Only process "add" data...
@@ -629,10 +626,7 @@ browse_local_callback(
                   "interfaceIndex=%d, errorCode=%d, serviceName=\"%s\", "
                  "regtype=\"%s\", replyDomain=\"%s\", context=%p)\n",
           sdRef, flags, interfaceIndex, errorCode,
-         serviceName ? serviceName : "(null)",
-         regtype ? regtype : "(null)",
-         replyDomain ? replyDomain : "(null)",
-         context);
+         serviceName, regtype, replyDomain, context);
 
  /*
   * Only process "add" data...
@@ -907,7 +901,7 @@ get_device(cups_array_t *devices,   /* I - Device array */
                                    replyDomain);
 #else /* HAVE_AVAHI */
        avahi_service_name_join(fullName, kDNSServiceMaxDomainName,
-                                serviceName, regtype, replyDomain);
+                               serviceName, regtype, replyDomain);
 #endif /* HAVE_DNSSD */
 
        free(device->fullName);
index 73491452df667621e0601047d133f2656549067a..a0736a8bb6a3d6de5c70ea49388040cb8f0665f5 100644 (file)
@@ -66,7 +66,8 @@ typedef struct _cups_monitor_s                /**** Monitoring data ****/
                        *resource;      /* Resource path */
   int                  port,           /* Port number */
                        version,        /* IPP version */
-                       job_id;         /* Job ID for submitted job */
+                       job_id,         /* Job ID for submitted job */
+                       get_job_attrs;  /* Support Get-Job-Attributes? */
   const char           *job_name;      /* Job name for submitted job */
   http_encryption_t    encryption;     /* Use encryption? */
   ipp_jstate_t         job_state;      /* Current job state */
@@ -241,6 +242,7 @@ main(int  argc,                             /* I - Number of command-line args */
   ipp_attribute_t *printer_state;      /* printer-state attribute */
   ipp_attribute_t *printer_accepting;  /* printer-is-accepting-jobs */
   int          create_job = 0,         /* Does printer support Create-Job? */
+               get_job_attrs = 0,      /* Does printer support Get-Job-Attributes? */
                send_document = 0,      /* Does printer support Send-Document? */
                validate_job = 0;       /* Does printer support Validate-Job? */
   int          copies,                 /* Number of copies for job */
@@ -1074,6 +1076,8 @@ main(int  argc,                           /* I - Number of command-line args */
          create_job = 1;
         else if (operations_sup->values[i].integer == IPP_SEND_DOCUMENT)
          send_document = 1;
+        else if (operations_sup->values[i].integer == IPP_GET_JOB_ATTRIBUTES)
+         get_job_attrs = 1;
       }
 
       if (!send_document)
@@ -1081,6 +1085,9 @@ main(int  argc,                           /* I - Number of command-line args */
         fputs("DEBUG: Printer supports Create-Job but not Send-Document.\n",
               stderr);
         create_job = 0;
+
+       update_reasons(NULL, "+cups-ipp-conformance-failure-report,"
+                             "cups-ipp-missing-send-document");
       }
 
       if (!validate_job)
@@ -1262,6 +1269,7 @@ main(int  argc,                           /* I - Number of command-line args */
   monitor.port          = port;
   monitor.version       = version;
   monitor.job_id        = 0;
+  monitor.get_job_attrs = get_job_attrs;
   monitor.encryption    = cupsEncryption();
   monitor.job_state     = IPP_JOB_PENDING;
   monitor.printer_state = IPP_PRINTER_IDLE;
@@ -1305,6 +1313,8 @@ main(int  argc,                           /* I - Number of command-line args */
       _cupsLangPrintFilter(stderr, "INFO", _("The printer is in use."));
       sleep(10);
     }
+    else if (ipp_status == IPP_DOCUMENT_FORMAT)
+      goto cleanup;
     else if (ipp_status == IPP_FORBIDDEN ||
             ipp_status == IPP_AUTHENTICATION_CANCELED)
     {
@@ -1328,7 +1338,8 @@ main(int  argc,                           /* I - Number of command-line args */
                           "cups-ipp-missing-validate-job");
       break;
     }
-    else if (ipp_status < IPP_REDIRECTION_OTHER_SITE)
+    else if (ipp_status < IPP_REDIRECTION_OTHER_SITE ||
+             ipp_status == IPP_BAD_REQUEST)
       break;
   }
 
@@ -1658,7 +1669,7 @@ main(int  argc,                           /* I - Number of command-line args */
     * Wait for the job to complete...
     */
 
-    if (!job_id || !waitjob)
+    if (!job_id || !waitjob || !get_job_attrs)
       continue;
 
     _cupsLangPrintFilter(stderr, "INFO", _("Waiting for job to complete."));
@@ -1701,7 +1712,7 @@ main(int  argc,                           /* I - Number of command-line args */
       response   = cupsDoRequest(http, request, resource);
       ipp_status = cupsLastError();
 
-      if (ipp_status == IPP_NOT_FOUND)
+      if (ipp_status == IPP_NOT_FOUND || ipp_status == IPP_NOT_POSSIBLE)
       {
        /*
         * Job has gone away and/or the server has no job history...
@@ -1723,7 +1734,6 @@ main(int  argc,                           /* I - Number of command-line args */
       else
       {
        if (ipp_status != IPP_SERVICE_UNAVAILABLE &&
-           ipp_status != IPP_NOT_POSSIBLE &&
            ipp_status != IPP_PRINTER_BUSY)
        {
          ippDelete(response);
@@ -1871,13 +1881,16 @@ main(int  argc,                         /* I - Number of command-line args */
     return (CUPS_BACKEND_AUTH_REQUIRED);
   else if (ipp_status == IPP_INTERNAL_ERROR)
     return (CUPS_BACKEND_STOP);
-  else if (ipp_status == IPP_DOCUMENT_FORMAT ||
-           ipp_status == IPP_CONFLICT)
+  else if (ipp_status == IPP_CONFLICT)
     return (CUPS_BACKEND_FAILED);
-  else if (ipp_status == IPP_REQUEST_VALUE || job_canceled < 0)
+  else if (ipp_status == IPP_REQUEST_VALUE ||
+           ipp_status == IPP_DOCUMENT_FORMAT || job_canceled < 0)
   {
     if (ipp_status == IPP_REQUEST_VALUE)
       _cupsLangPrintFilter(stderr, "ERROR", _("Print job too large."));
+    else if (ipp_status == IPP_DOCUMENT_FORMAT)
+      _cupsLangPrintFilter(stderr, "ERROR",
+                           _("Printer cannot print supplied content."));
     else
       _cupsLangPrintFilter(stderr, "ERROR", _("Print job canceled at printer."));
 
@@ -2123,7 +2136,8 @@ monitor_printer(
       * Check the status of the job itself...
       */
 
-      job_op  = monitor->job_id > 0 ? IPP_GET_JOB_ATTRIBUTES : IPP_GET_JOBS;
+      job_op  = (monitor->job_id > 0 && monitor->get_job_attrs) ?
+                    IPP_GET_JOB_ATTRIBUTES : IPP_GET_JOBS;
       request = ippNewRequest(job_op);
       request->request.op.version[0] = monitor->version / 10;
       request->request.op.version[1] = monitor->version % 10;
@@ -2321,7 +2335,7 @@ new_request(
     fprintf(stderr, "DEBUG: job-name=\"%s\"\n", title);
   }
 
-  if (format)
+  if (format && op != IPP_CREATE_JOB)
   {
     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE,
                 "document-format", NULL, format);
@@ -2329,7 +2343,7 @@ new_request(
   }
 
 #ifdef HAVE_LIBZ
-  if (compression)
+  if (compression && op != IPP_CREATE_JOB)
   {
     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
                 "compression", NULL, compression);
@@ -2569,7 +2583,7 @@ new_request(
       * When talking to another CUPS server, send all options...
       */
 
-      cupsEncodeOptions(request, num_options, options);
+      cupsEncodeOptions2(request, num_options, options, IPP_TAG_JOB);
     }
 
     if (copies > 1 && (!pc || copies <= pc->max_copies))
index 75dc9dc7a1b001ddec0e2aa8d68849c42790a3e4..380dd793d3e91de6c80e6849c552cc15cd4179b6 100644 (file)
@@ -49,6 +49,9 @@
 #define CUPS_CLEANER_NEAR_EOL  0x0400  /* Proposed JPS3 */
 #define CUPS_CLEANER_LIFE_OVER 0x0800  /* Proposed JPS3 */
 
+#define CUPS_SNMP_NONE         0x0000
+#define CUPS_SNMP_CAPACITY     0x0001  /* Supply levels reported as percentages */
+
 
 /*
  * Local structures...
@@ -79,6 +82,8 @@ static http_addr_t    current_addr;   /* Current address */
 static int             current_state = -1;
                                        /* Current device state bits */
 static int             charset = -1;   /* Character set for supply names */
+static unsigned                quirks = CUPS_SNMP_NONE;
+                                       /* Quirks we have to work around */
 static int             num_supplies = 0;
                                        /* Number of supplies found */
 static backend_supplies_t supplies[CUPS_MAX_SUPPLIES];
@@ -246,6 +251,9 @@ backendSNMPSupplies(
     {
       if (supplies[i].max_capacity > 0 && supplies[i].level >= 0)
        percent = 100 * supplies[i].level / supplies[i].max_capacity;
+      else if (supplies[i].level >= 0 && supplies[i].level <= 100 &&
+               (quirks & CUPS_SNMP_CAPACITY))
+        percent = supplies[i].level;
       else
         percent = 50;
 
@@ -308,7 +316,8 @@ backendSNMPSupplies(
       if (i)
         *ptr++ = ',';
 
-      if (supplies[i].max_capacity > 0 && supplies[i].level >= 0)
+      if ((supplies[i].max_capacity > 0 || (quirks & CUPS_SNMP_CAPACITY)) &&
+          supplies[i].level >= 0)
         sprintf(ptr, "%d", percent);
       else
         strcpy(ptr, "-1");
@@ -506,6 +515,12 @@ backend_init_supplies(
     return;
   }
 
+  if ((ppdattr = ppdFindAttr(ppd, "cupsSNMPQuirks", NULL)) != NULL)
+  {
+    if (!_cups_strcasecmp(ppdattr->value, "capacity"))
+      quirks |= CUPS_SNMP_CAPACITY;
+  }
+
   ppdClose(ppd);
 
  /*
@@ -932,7 +947,8 @@ backend_walk_cb(cups_snmp_t *packet,        /* I - SNMP packet */
 
     supplies[i - 1].level = packet->object_value.integer;
   }
-  else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesMaxCapacity))
+  else if (_cupsSNMPIsOIDPrefixed(packet, prtMarkerSuppliesMaxCapacity) &&
+           !(quirks & CUPS_SNMP_CAPACITY))
   {
    /*
     * Get max capacity...
index 103a0e30bbec861f14f9dccad2128ef6da5e2041..5811fde1f0dfb3dd6a244efc0a079608e0201e27 100644 (file)
@@ -537,10 +537,10 @@ print_device(const char *uri,             /* I - Device URI */
    /*
     * If it didn't exit abort the pending read and wait an additional second...
     */
-  
+
     if (!g.read_thread_done)
     {
-      fputs("DEBUG: Read thread still active, aborting the pending read...\n", 
+      fputs("DEBUG: Read thread still active, aborting the pending read...\n",
            stderr);
 
       g.wait_eof = 0;
@@ -548,7 +548,7 @@ print_device(const char *uri,               /* I - Device URI */
       gettimeofday(&tv, NULL);
       cond_timeout.tv_sec  = tv.tv_sec + 1;
       cond_timeout.tv_nsec = tv.tv_usec * 1000;
-  
+
       while (!g.read_thread_done)
       {
        if (pthread_cond_timedwait(&g.read_thread_cond, &g.read_thread_mutex,
@@ -602,8 +602,8 @@ close_device(usb_printer_t *printer)        /* I - Printer */
 
     int number;                                /* Interface number */
 
-    libusb_get_device_descriptor (printer->device, &devdesc);
-    libusb_get_config_descriptor (printer->device, printer->conf, &confptr);
+    libusb_get_device_descriptor(printer->device, &devdesc);
+    libusb_get_config_descriptor(printer->device, printer->conf, &confptr);
     number = confptr->interface[printer->iface].
                  altsetting[printer->altset].bInterfaceNumber;
     libusb_release_interface(printer->handle, number);
@@ -694,7 +694,7 @@ find_device(usb_cb_t   cb,          /* I - Callback function */
       * a printer...
       */
 
-      libusb_get_device_descriptor (device, &devdesc);
+      libusb_get_device_descriptor(device, &devdesc);
 
       if (!devdesc.bNumConfigurations || !devdesc.idVendor ||
           !devdesc.idProduct)
@@ -702,7 +702,7 @@ find_device(usb_cb_t   cb,          /* I - Callback function */
 
       for (conf = 0; conf < devdesc.bNumConfigurations; conf ++)
       {
-       if (libusb_get_config_descriptor (device, conf, &confptr) < 0)
+       if (libusb_get_config_descriptor(device, conf, &confptr) < 0)
          continue;
         for (iface = 0, ifaceptr = confptr->interface;
             iface < confptr->bNumInterfaces;
@@ -950,7 +950,7 @@ make_device_uri(
   if ((sern = cupsGetOption("SERIALNUMBER", num_values, values)) == NULL)
     if ((sern = cupsGetOption("SERN", num_values, values)) == NULL)
       if ((sern = cupsGetOption("SN", num_values, values)) == NULL &&
-         ((libusb_get_device_descriptor (printer->device, &devdesc) >= 0) &&
+         ((libusb_get_device_descriptor(printer->device, &devdesc) >= 0) &&
           devdesc.iSerialNumber))
       {
        /*
@@ -1089,9 +1089,45 @@ open_device(usb_printer_t *printer,      /* I - Printer */
   if (libusb_open(printer->device, &printer->handle) < 0)
     return (-1);
 
+  printer->usblp_attached = 0;
+
   if (verbose)
     fputs("STATE: +connecting-to-device\n", stderr);
 
+  if ((errcode = libusb_get_device_descriptor (printer->device, &devdesc)) < 0)
+  {
+    fprintf(stderr, "DEBUG: Failed to get device descriptor, code: %d\n",
+           errcode);
+    goto error;
+  }
+
+ /*
+  * Get the "usblp" kernel module out of the way. This backend only
+  * works without the module attached.
+  */
+
+  errcode = libusb_kernel_driver_active(printer->handle, printer->iface);
+  if (errcode == 0)
+    printer->usblp_attached = 0;
+  else if (errcode == 1)
+  {
+    printer->usblp_attached = 1;
+    if ((errcode =
+        libusb_detach_kernel_driver(printer->handle, printer->iface)) < 0)
+    {
+      fprintf(stderr, "DEBUG: Failed to detach \"usblp\" module from %04x:%04x\n",
+             devdesc.idVendor, devdesc.idProduct);
+      goto error;
+    }
+  }
+  else
+  {
+    printer->usblp_attached = 0;
+    fprintf(stderr, "DEBUG: Failed to check whether %04x:%04x has the \"usblp\" kernel module attached\n",
+             devdesc.idVendor, devdesc.idProduct);
+    goto error;
+  }
+
  /*
   * Set the desired configuration, but only if it needs changing. Some
   * printers (e.g., Samsung) don't like libusb_set_configuration. It will
@@ -1106,8 +1142,8 @@ open_device(usb_printer_t *printer,       /* I - Printer */
                0, 0, (unsigned char *)&current, 1, 5000) < 0)
     current = 0;                       /* Assume not configured */
 
-  libusb_get_device_descriptor (printer->device, &devdesc);
-  libusb_get_config_descriptor (printer->device, printer->conf, &confptr);
+  libusb_get_device_descriptor(printer->device, &devdesc);
+  libusb_get_config_descriptor(printer->device, printer->conf, &confptr);
   number1 = confptr->bConfigurationValue;
 
   if (number1 != current)
@@ -1148,9 +1184,14 @@ open_device(usb_printer_t *printer,      /* I - Printer */
   else
   {
     printer->usblp_attached = 0;
-    fprintf(stderr, "DEBUG: Failed to check whether %04x:%04x has the \"usblp\" kernel module attached\n",
-             devdesc.idVendor, devdesc.idProduct);
-    goto error;
+
+    if (errcode != LIBUSB_ERROR_NOT_SUPPORTED)
+    {
+      fprintf(stderr,
+              "DEBUG: Failed to check whether %04x:%04x has the \"usblp\" "
+              "kernel module attached\n", devdesc.idVendor, devdesc.idProduct);
+      goto error;
+    }
   }
 
  /*
@@ -1163,11 +1204,13 @@ open_device(usb_printer_t *printer,     /* I - Printer */
   while ((errcode = libusb_claim_interface(printer->handle, number1)) < 0)
   {
     if (errcode != LIBUSB_ERROR_BUSY)
+    {
       fprintf(stderr,
               "DEBUG: Failed to claim interface %d for %04x:%04x: %s\n",
               number1, devdesc.idVendor, devdesc.idProduct, strerror(errno));
 
-    goto error;
+      goto error;
+    }
   }
 
  /*
@@ -1187,12 +1230,14 @@ open_device(usb_printer_t *printer,     /* I - Printer */
           < 0)
     {
       if (errcode != LIBUSB_ERROR_BUSY)
+      {
         fprintf(stderr,
                 "DEBUG: Failed to set alternate interface %d for %04x:%04x: "
                 "%s\n",
                 number2, devdesc.idVendor, devdesc.idProduct, strerror(errno));
 
-      goto error;
+       goto error;
+      }
     }
   }
 
index 27d73c55ceca86f9f16ef4b9318164cb395e10ca..7d30cc6e6d5cd6f4b12d39ddd77f51e0ff074dfd 100644 (file)
@@ -89,7 +89,7 @@ main(int  argc,                               /* I - Number of command-line arguments */
               cupsSetUser(argv[i]);
            }
            break;
-           
+
         case 'H' : /* Connect to host */
            if (argv[i][2] != '\0')
               cupsSetServer(argv[i] + 2);
@@ -401,8 +401,9 @@ main(int  argc,                             /* I - Number of command-line arguments */
 
     if (cupsFinishDocument(CUPS_HTTP_DEFAULT, printer) != IPP_OK)
     {
+      _cupsLangPrintf(stderr, "%s: %s", argv[0], cupsLastErrorString());
       cupsCancelJob2(CUPS_HTTP_DEFAULT, printer, job_id, 0);
-      job_id = 0;
+      return (1);
     }
   }
 
index 5772828893ed481bb21018226669847669e50b7c..4aee5d9a41cc0c36e8c81d5dac6d5e0e75ddcc96 100644 (file)
@@ -3,7 +3,7 @@
  *
  *   Xcode documentation set generator.
  *
- *   Copyright 2007-2011 by Apple Inc.
+ *   Copyright 2007-2012 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products.
  *
  *   These coded instructions, statements, and computer programs are the
@@ -31,7 +31,7 @@
  * Include necessary headers...
  */
 
-#include "cgi.h"
+#include "cgi-private.h"
 #include <errno.h>
 
 
index de6996d47237c38cc5c574af344f159268f33d1d..b8c74052366c0622eab5bf248bc1653025def672 100644 (file)
@@ -51,7 +51,6 @@ AC_PROG_RANLIB
 AC_PATH_PROG(AR,ar)
 AC_PATH_PROG(CHMOD,chmod)
 AC_PATH_PROG(GZIP,gzip)
-AC_PATH_PROG(HTMLDOC,htmldoc)
 AC_PATH_PROG(LD,ld)
 AC_PATH_PROG(LN,ln)
 AC_PATH_PROG(MV,mv)
index 3ed91f79bdf0b192d964669fa31455a3dc8edf04..426637a20e74cf120a8b5ab0dff17ada7bab0f45 100644 (file)
@@ -43,8 +43,6 @@ if test "x$DNSSD_BACKEND" = x -a x$enable_dnssd != xno; then
                        Darwin*)
                                # Darwin and MacOS X...
                                AC_DEFINE(HAVE_DNSSD)
-                               AC_DEFINE(HAVE_COREFOUNDATION)
-                               AC_DEFINE(HAVE_SYSTEMCONFIGURATION)
                                DNSSDLIBS="-framework CoreFoundation -framework SystemConfiguration"
                                DNSSD_BACKEND="dnssd"
                                ;;
index 157ed0f42b891f774f6922df8d4d8f3652c4a6dc..28d5d3482b76e8d91cb510228b14709cb477069a 100644 (file)
@@ -124,7 +124,7 @@ if test x$enable_ssl != xno; then
 
     dnl Check for the OpenSSL library last...
     if test $have_ssl = 0 -a "x$enable_openssl" != "xno"; then
-       AC_CHECK_HEADER(openssl/ssl.h,
+       AC_CHECK_HEADER(openssl/ssl.h,[
            dnl Save the current libraries so the crypto stuff isn't always
            dnl included...
            SAVELIBS="$LIBS"
@@ -149,14 +149,16 @@ if test x$enable_ssl != xno; then
                    $libcrypto)
 
                if test "x${SSLLIBS}" != "x"; then
-                   LIBS="$SAVELIBS $SSLLIBS"
-                   AC_CHECK_FUNC(SSL_set_tlsext_host_name,
-                       AC_DEFINE(HAVE_SSL_SET_TLSEXT_HOST_NAME))
                    break
                fi
            done
 
-           LIBS="$SAVELIBS")
+           if test "x${SSLLIBS}" != "x"; then
+               LIBS="$SAVELIBS $SSLLIBS"
+               AC_CHECK_FUNCS(SSL_set_tlsext_host_name)
+           fi
+
+           LIBS="$SAVELIBS"])
     fi
 fi
 
index 32a2d715cda88508c31916391671499710b10fbc..9498b7f5e567dd5e03d625a552e62cff426fbbc8 100644 (file)
 #define CUPS_GHOSTSCRIPT "/usr/bin/gs"
 
 
-/*
- * Do we have Darwin's CoreFoundation and SystemConfiguration frameworks?
- */
-
-#undef HAVE_COREFOUNDATION
-#undef HAVE_SYSTEMCONFIGURATION
-
-
 /*
  * Do we have CoreFoundation public and private headers?
  */
index e2c0239ade498a282722dc2e3be34987bfb6f8a6..816e725525cdac3b28393a4e634b37816ea6ef34 100644 (file)
@@ -190,13 +190,22 @@ typedef struct _cups_media_db_s           /* Media database */
                                         * millimeters */
 } _cups_media_db_t;
 
+typedef struct _cups_dconstres_s       /* Constraint/resolver */
+{
+  char *name;                          /* Name of resolver */
+  ipp_t        *collection;                    /* Collection containing attrs */
+} _cups_dconstres_t;
+
 struct _cups_dinfo_s                   /* Destination capability and status
                                         * information */
 {
   const char           *uri;           /* Printer URI */
   char                 *resource;      /* Resource path */
   ipp_t                        *attrs;         /* Printer attributes */
+  int                  num_defaults;   /* Number of default options */
+  cups_option_t                *defaults;      /* Default options */
   cups_array_t         *constraints;   /* Job constraints */
+  cups_array_t         *resolvers;     /* Job resolvers */
   cups_array_t         *localizations; /* Localization information */
   cups_array_t         *media_db;      /* Media database */
   _cups_media_db_t     min_size,       /* Minimum size */
index dc4f0879bf7e4a081c5e8975ec003d601e6d0ac2..f0792c728fa7a1e4070b56a35fd65690061f9e0b 100644 (file)
@@ -196,7 +196,9 @@ cupsCreateDestJob(
   if (title)
     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
                  title);
-  cupsEncodeOptions(request, num_options, options);
+
+  cupsEncodeOptions2(request, num_options, options, IPP_TAG_JOB);
+  cupsEncodeOptions2(request, num_options, options, IPP_TAG_SUBSCRIPTION);
 
  /*
   * Send the request and get the job-id...
index 375386909471ec1015ce35eb337c9485590afbc3..ad709ee82e286ed0390f8f80a5925d348490d240 100644 (file)
  *
  * Contents:
  *
- *   cupsLocalizeDestOption() - Get the localized string for a destination
- *                             option.
- *   cupsLocalizeDestValue()  - Get the localized string for a destination
- *                             option+value pair.
+ *   cupsLocalizeDestOption()   - Get the localized string for a destination
+ *                                option.
+ *   cupsLocalizeDestValue()    - Get the localized string for a destination
+ *                                option+value pair.
+ *   cups_create_localizations() - Create the localizations array for a
+ *                                destination.
+ *   cups_read_strings()        - Read a pair of strings from a .strings file.
+ *   cups_scan_strings()        - Scan a quoted string.
  */
 
 /*
 #include "cups-private.h"
 
 
+/*
+ * Local functions...
+ */
+
+static void    cups_create_localizations(http_t *http, cups_dinfo_t *dinfo);
+static int     cups_read_strings(cups_file_t *fp, char *buffer, size_t bufsize,
+                                 char **id, char **str);
+static char    *cups_scan_strings(char *buffer);
+
+
 /*
  * 'cupsLocalizeDestOption()' - Get the localized string for a destination
  *                              option.
  *
- * The returned string is stored in the localization array and will become
- * invalid if the localization array is deleted.
+ * The returned string is stored in the destination information and will become
+ * invalid if the destination information is deleted.
  *
  * @since CUPS 1.6/OS X 10.8@
  */
@@ -45,7 +59,25 @@ cupsLocalizeDestOption(
     cups_dinfo_t *dinfo,               /* I - Destination information */
     const char   *option)              /* I - Option to localize */
 {
-  return (option);
+  _cups_message_t      key,            /* Search key */
+                       *match;         /* Matching entry */
+
+
+  if (!http || !dest || !dinfo)
+    return (option);
+
+  if (!dinfo->localizations)
+    cups_create_localizations(http, dinfo);
+
+  if (cupsArrayCount(dinfo->localizations) == 0)
+    return (option);
+
+  key.id = (char *)option;
+  if ((match = (_cups_message_t *)cupsArrayFind(dinfo->localizations,
+                                                &key)) != NULL)
+    return (match->str);
+  else
+    return (option);
 }
 
 
@@ -53,8 +85,8 @@ cupsLocalizeDestOption(
  * 'cupsLocalizeDestValue()' - Get the localized string for a destination
  *                             option+value pair.
  *
- * The returned string is stored in the localization array and will become
- * invalid if the localization array is deleted.
+ * The returned string is stored in the destination information and will become
+ * invalid if the destination information is deleted.
  *
  * @since CUPS 1.6/OS X 10.8@
  */
@@ -67,10 +99,288 @@ cupsLocalizeDestValue(
     const char   *option,              /* I - Option to localize */
     const char   *value)               /* I - Value to localize */
 {
-  return (value);
+  _cups_message_t      key,            /* Search key */
+                       *match;         /* Matching entry */
+  char                 pair[256];      /* option.value pair */
+
+
+  if (!http || !dest || !dinfo)
+    return (value);
+
+  if (!dinfo->localizations)
+    cups_create_localizations(http, dinfo);
+
+  if (cupsArrayCount(dinfo->localizations) == 0)
+    return (value);
+
+  snprintf(pair, sizeof(pair), "%s.%s", option, value);
+  key.id = pair;
+  if ((match = (_cups_message_t *)cupsArrayFind(dinfo->localizations,
+                                                &key)) != NULL)
+    return (match->str);
+  else
+    return (value);
+}
+
+
+/*
+ * 'cups_create_localizations()' - Create the localizations array for a
+ *                                 destination.
+ */
+
+static void
+cups_create_localizations(
+    http_t       *http,                        /* I - Connection to destination */
+    cups_dinfo_t *dinfo)               /* I - Destination informations */
+{
+  http_t               *http2;         /* Connection for strings file */
+  http_status_t                status;         /* Request status */
+  ipp_attribute_t      *attr;          /* "printer-strings-uri" attribute */
+  char                 scheme[32],     /* URI scheme */
+                       userpass[256],  /* Username/password info */
+                       hostname[256],  /* Hostname */
+                       resource[1024], /* Resource */
+                       http_hostname[256],
+                                       /* Hostname of connection */
+                       tempfile[1024]; /* Temporary filename */
+  int                  port;           /* Port number */
+  http_encryption_t    encryption;     /* Encryption to use */
+  cups_file_t          *temp;          /* Temporary file */
+
+
+ /*
+  * Create an empty message catalog...
+  */
+
+  dinfo->localizations = _cupsMessageNew(NULL);
+
+ /*
+  * See if there are any localizations...
+  */
+
+  if ((attr = ippFindAttribute(dinfo->attrs, "printer-strings-uri",
+                               IPP_TAG_URI)) == NULL)
+  {
+   /*
+    * Nope...
+    */
+
+    DEBUG_puts("4cups_create_localizations: No printer-strings-uri (uri) "
+               "value.");
+    return;                            /* Nope */
+  }
+
+ /*
+  * Pull apart the URI and determine whether we need to try a different
+  * server...
+  */
+
+  if (httpSeparateURI(HTTP_URI_CODING_ALL, attr->values[0].string.text,
+                      scheme, sizeof(scheme), userpass, sizeof(userpass),
+                      hostname, sizeof(hostname), &port, resource,
+                      sizeof(resource)) < HTTP_URI_OK)
+  {
+    DEBUG_printf(("4cups_create_localizations: Bad printer-strings-uri value "
+                  "\"%s\".", attr->values[0].string.text));
+    return;
+  }
+
+  httpGetHostname(http, http_hostname, sizeof(http_hostname));
+
+  if (!_cups_strcasecmp(http_hostname, hostname) &&
+      port == _httpAddrPort(http->hostaddr))
+  {
+   /*
+    * Use the same connection...
+    */
+
+    http2 = http;
+  }
+  else
+  {
+   /*
+    * Connect to the alternate host...
+    */
+
+    if (!strcmp(scheme, "https"))
+      encryption = HTTP_ENCRYPT_ALWAYS;
+    else
+      encryption = HTTP_ENCRYPT_IF_REQUESTED;
+
+    if ((http2 = httpConnectEncrypt(hostname, port, encryption)) == NULL)
+    {
+      DEBUG_printf(("4cups_create_localizations: Unable to connect to "
+                    "%s:%d: %s", hostname, port, cupsLastErrorString()));
+      return;
+    }
+  }
+
+ /*
+  * Get a temporary file...
+  */
+
+  if ((temp = cupsTempFile2(tempfile, sizeof(tempfile))) == NULL)
+  {
+    DEBUG_printf(("4cups_create_localizations: Unable to create temporary "
+                  "file: %s", cupsLastErrorString()));
+    if (http2 != http)
+      httpClose(http2);
+    return;
+  }
+
+  status = cupsGetFd(http2, resource, cupsFileNumber(temp));
+
+  DEBUG_printf(("4cups_create_localizations: GET %s = %s", resource,
+                httpStatus(status)));
+
+  if (status == HTTP_OK)
+  {
+   /*
+    * Got the file, read it...
+    */
+
+    char               buffer[8192],   /* Message buffer */
+                       *id,            /* ID string */
+                       *str;           /* Translated message */
+    _cups_message_t    *m;             /* Current message */
+
+    lseek(cupsFileNumber(temp), 0, SEEK_SET);
+
+    while (cups_read_strings(temp, buffer, sizeof(buffer), &id, &str))
+    {
+      if ((m = malloc(sizeof(_cups_message_t))) == NULL)
+        break;
+
+      m->id  = strdup(id);
+      m->str = strdup(str);
+
+      if (m->id && m->str)
+        cupsArrayAdd(dinfo->localizations, m);
+      else
+      {
+        if (m->id)
+          free(m->id);
+
+        if (m->str)
+          free(m->str);
+
+        free(m);
+        break;
+      }
+    }
+  }
+
+  DEBUG_printf(("4cups_create_localizations: %d messages loaded.",
+                cupsArrayCount(dinfo->localizations)));
+
+ /*
+  * Cleanup...
+  */
+
+  unlink(tempfile);
+  cupsFileClose(temp);
+
+  if (http2 != http)
+    httpClose(http2);
+}
+
+
+/*
+ * 'cups_read_strings()' - Read a pair of strings from a .strings file.
+ */
+
+static int                             /* O - 1 on success, 0 on failure */
+cups_read_strings(cups_file_t *strings,        /* I - .strings file */
+                  char        *buffer, /* I - Line buffer */
+                  size_t      bufsize, /* I - Size of line buffer */
+                 char        **id,     /* O - Pointer to ID string */
+                 char        **str)    /* O - Pointer to translation string */
+{
+  char *bufptr;                        /* Pointer into buffer */
+
+
+  while (cupsFileGets(strings, buffer, bufsize))
+  {
+    if (buffer[0] != '\"')
+      continue;
+
+    *id    = buffer + 1;
+    bufptr = cups_scan_strings(buffer);
+
+    if (*bufptr != '\"')
+      continue;
+
+    *bufptr++ = '\0';
+
+    while (*bufptr && *bufptr != '\"')
+      bufptr ++;
+
+    if (!*bufptr)
+      continue;
+
+    *str   = bufptr + 1;
+    bufptr = cups_scan_strings(bufptr);
+
+    if (*bufptr != '\"')
+      continue;
+
+    *bufptr = '\0';
+
+    return (1);
+  }
+
+  return (0);
+}
+
+
+/*
+ * 'cups_scan_strings()' - Scan a quoted string.
+ */
+
+static char *                          /* O - End of string */
+cups_scan_strings(char *buffer)                /* I - Start of string */
+{
+  char *bufptr;                        /* Pointer into string */
+
+
+  for (bufptr = buffer + 1; *bufptr && *bufptr != '\"'; bufptr ++)
+  {
+    if (*bufptr == '\\')
+    {
+      if (bufptr[1] >= '0' && bufptr[1] <= '3' &&
+         bufptr[2] >= '0' && bufptr[2] <= '7' &&
+         bufptr[3] >= '0' && bufptr[3] <= '7')
+      {
+       /*
+       * Decode \nnn octal escape...
+       */
+
+       *bufptr = ((((bufptr[1] - '0') << 3) | (bufptr[2] - '0')) << 3) |
+                 (bufptr[3] - '0');
+       _cups_strcpy(bufptr + 1, bufptr + 4);
+      }
+      else
+      {
+       /*
+       * Decode \C escape...
+       */
+
+       _cups_strcpy(bufptr, bufptr + 1);
+       if (*bufptr == 'n')
+         *bufptr = '\n';
+       else if (*bufptr == 'r')
+         *bufptr = '\r';
+       else if (*bufptr == 't')
+         *bufptr = '\t';
+      }
+    }
+  }
+
+  return (bufptr);
 }
 
 
+
 /*
  * End of "$Id$".
  */
index cfdf6077e58dfdcc6d0aefb7122061bb301d4d6a..32616a683c1426637919acadf6b3e3cb2825b093 100644 (file)
  *
  * Contents:
  *
-*   cupsCheckDestSupported() - Check that the option and value are supported
- *                             by the destination.
- *   cupsCopyDestConflicts()  - Get conflicts and resolutions for a new
- *                             option/value pair.
- *   cupsCopyDestInfo()       - Get the supported values/capabilities for the
- *                             destination.
- *   cupsFreeDestInfo()       - Free destination information obtained using
- *                             @link cupsCopyDestInfo@.
- *   cupsGetDestMediaByName() - Get media names, dimensions, and margins.
- *   cupsGetDestMediaBySize() - Get media names, dimensions, and margins.
- *   cups_compare_media_db()  - Compare two media entries.
- *   cups_copy_media_db()     - Copy a media entry.
- *   cups_create_media_db()   - Create the media database.
- *   cups_free_media_cb()     - Free a media entry.
- *   cups_get_media_db()      - Lookup the media entry for a given size.
- *   cups_is_close_media_db() - Compare two media entries to see if they are
- *                             close to the same size.
+ *   cupsCheckDestSupported()  - Check that the option and value are supported
+ *                              by the destination.
+ *   cupsCopyDestConflicts()   - Get conflicts and resolutions for a new
+ *                              option/value pair.
+ *   cupsCopyDestInfo()        - Get the supported values/capabilities for the
+ *                              destination.
+ *   cupsFreeDestInfo()        - Free destination information obtained using
+ *                              @link cupsCopyDestInfo@.
+ *   cupsGetDestMediaByName()  - Get media names, dimensions, and margins.
+ *   cupsGetDestMediaBySize()  - Get media names, dimensions, and margins.
+ *   cups_add_dconstres()      - Add a constraint or resolver to an array.
+ *   cups_compare_dconstres()  - Compare to resolver entries.
+ *   cups_compare_media_db()   - Compare two media entries.
+ *   cups_copy_media_db()      - Copy a media entry.
+ *   cups_create_constraints() - Create the constraints and resolvers arrays.
+ *   cups_create_defaults()    - Create the -default option array.
+ *   cups_create_media_db()    - Create the media database.
+ *   cups_free_media_cb()      - Free a media entry.
+ *   cups_get_media_db()       - Lookup the media entry for a given size.
+ *   cups_is_close_media_db()  - Compare two media entries to see if they are
+ *                              close to the same size.
+ *   cups_test_constraints()   - Test constraints.
  */
 
 /*
  * Local functions...
  */
 
+static void            cups_add_dconstres(cups_array_t *a, ipp_t *collection);
+static int             cups_compare_dconstres(_cups_dconstres_t *a,
+                                              _cups_dconstres_t *b);
 static int             cups_compare_media_db(_cups_media_db_t *a,
                                              _cups_media_db_t *b);
 static _cups_media_db_t        *cups_copy_media_db(_cups_media_db_t *mdb);
+static void            cups_create_constraints(cups_dinfo_t *dinfo);
+static void            cups_create_defaults(cups_dinfo_t *dinfo);
 static void            cups_create_media_db(cups_dinfo_t *dinfo);
 static void            cups_free_media_db(_cups_media_db_t *mdb);
 static int             cups_get_media_db(cups_dinfo_t *dinfo,
@@ -55,6 +65,14 @@ static int           cups_get_media_db(cups_dinfo_t *dinfo,
                                          cups_size_t *size);
 static int             cups_is_close_media_db(_cups_media_db_t *a,
                                               _cups_media_db_t *b);
+static cups_array_t    *cups_test_constraints(cups_dinfo_t *dinfo,
+                                              const char *new_option,
+                                              const char *new_value,
+                                              int num_options,
+                                              cups_option_t *options,
+                                              int *num_conflicts,
+                                              cups_option_t **conflicts);
+
 
 /*
  * 'cupsCheckDestSupported()' - Check that the option and value are supported
@@ -176,6 +194,15 @@ cupsCheckDestSupported(
       case IPP_TAG_BOOLEAN :
           return (attr->values[0].boolean);
 
+      case IPP_TAG_RANGE :
+          int_value = atoi(value);
+
+          for (i = 0; i < attr->num_values; i ++)
+            if (int_value >= attr->values[i].range.lower &&
+                int_value <= attr->values[i].range.upper)
+              return (1);
+          break;
+
       case IPP_TAG_RESOLUTION :
           if (sscanf(value, "%dx%d%15s", &xres_value, &yres_value, temp) != 3)
           {
@@ -239,7 +266,8 @@ cupsCheckDestSupported(
  * user.  "new_option" and "new_value" are the setting the user has just
  * changed.
  *
- * Returns 1 if there is a conflict and 0 otherwise.
+ * Returns 1 if there is a conflict, 0 if there are no conflicts, and -1 if
+ * there was an unrecoverable error such as a resolver loop.
  *
  * If "num_conflicts" and "conflicts" are not NULL, they are set to contain the
  * list of conflicting option/value pairs.  Similarly, if "num_resolved" and
@@ -252,7 +280,7 @@ cupsCheckDestSupported(
  * @since CUPS 1.6/OS X 10.8@
  */
 
-int                                    /* O - 1 if there is a conflict */
+int                                    /* O - 1 if there is a conflict, 0 if none, -1 on error */
 cupsCopyDestConflicts(
     http_t        *http,               /* I - Connection to destination */
     cups_dest_t   *dest,               /* I - Destination */
@@ -266,6 +294,27 @@ cupsCopyDestConflicts(
     int           *num_resolved,       /* O - Number of options to resolve */
     cups_option_t **resolved)          /* O - Resolved options */
 {
+  int          i,                      /* Looping var */
+               have_conflicts = 0,     /* Do we have conflicts? */
+               changed,                /* Did we change something? */
+               tries,                  /* Number of tries for resolution */
+               num_myconf = 0,         /* My number of conflicting options */
+               num_myres = 0;          /* My number of resolved options */
+  cups_option_t        *myconf = NULL,         /* My conflicting options */
+               *myres = NULL,          /* My resolved options */
+               *myoption,              /* My current option */
+               *option;                /* Current option */
+  cups_array_t *active,                /* Active conflicts */
+               *pass = NULL,           /* Resolvers for this pass */
+               *resolvers = NULL,      /* Resolvers we have used */
+               *test;                  /* Test array for conflicts */
+  _cups_dconstres_t *c,                        /* Current constraint */
+               *r;                     /* Current resolver */
+  ipp_attribute_t *attr;               /* Current attribute */
+  char         value[2048];            /* Current attribute value as string */
+  const char   *myvalue;               /* Current value of an option */
+
+
  /*
   * Clear returned values...
   */
@@ -286,18 +335,223 @@ cupsCopyDestConflicts(
   * Range check input...
   */
 
-  if (!http || !dest || !dinfo || !new_option || !new_value ||
+  if (!http || !dest || !dinfo ||
       (num_conflicts != NULL) != (conflicts != NULL) ||
       (num_resolved != NULL) != (resolved != NULL))
     return (0);
 
  /*
-  * Check for and resolve any conflicts...
+  * Load constraints as needed...
   */
 
-  /* TODO: implement me! */
+  if (!dinfo->constraints)
+    cups_create_constraints(dinfo);
 
-  return (0);
+  if (cupsArrayCount(dinfo->constraints) == 0)
+    return (0);
+
+  if (!dinfo->num_defaults)
+    cups_create_defaults(dinfo);
+
+ /*
+  * If we are resolving, create a shadow array...
+  */
+
+  if (num_resolved)
+  {
+    for (i = num_options, option = options; i > 0; i --, option ++)
+      num_myres = cupsAddOption(option->name, option->value, num_myres, &myres);
+
+    if (new_option && new_value)
+      num_myres = cupsAddOption(new_option, new_value, num_myres, &myres);
+  }
+  else
+  {
+    num_myres = num_options;
+    myres     = options;
+  }
+
+ /*
+  * Check for any conflicts...
+  */
+
+  if (num_resolved)
+    pass = cupsArrayNew((cups_array_func_t)cups_compare_dconstres, NULL);
+
+  for (tries = 0; tries < 100; tries ++)
+  {
+   /*
+    * Check for any conflicts...
+    */
+
+    if (num_conflicts || num_resolved)
+    {
+      cupsFreeOptions(num_myconf, myconf);
+
+      num_myconf = 0;
+      myconf     = NULL;
+      active     = cups_test_constraints(dinfo, new_option, new_value,
+                                         num_myres, myres, &num_myconf,
+                                         &myconf);
+    }
+    else
+      active = cups_test_constraints(dinfo, new_option, new_value, num_myres,
+                                    myres, NULL, NULL);
+
+    have_conflicts = (active != NULL);
+
+    if (!active || !num_resolved)
+      break;                           /* All done */
+
+   /*
+    * Scan the constraints that were triggered to apply resolvers...
+    */
+
+    if (!resolvers)
+      resolvers = cupsArrayNew((cups_array_func_t)cups_compare_dconstres, NULL);
+
+    for (c = (_cups_dconstres_t *)cupsArrayFirst(active), changed = 0;
+         c;
+         c = (_cups_dconstres_t *)cupsArrayNext(active))
+    {
+      if (cupsArrayFind(pass, c))
+        continue;                      /* Already applied this resolver... */
+
+      if (cupsArrayFind(resolvers, c))
+      {
+        DEBUG_printf(("1cupsCopyDestConflicts: Resolver loop with %s.",
+                      c->name));
+        have_conflicts = -1;
+        goto cleanup;
+      }
+
+      if ((r = cupsArrayFind(dinfo->resolvers, c)) == NULL)
+      {
+        DEBUG_printf(("1cupsCopyDestConflicts: Resolver %s not found.",
+                      c->name));
+        have_conflicts = -1;
+        goto cleanup;
+      }
+
+     /*
+      * Add the options from the resolver...
+      */
+
+      cupsArrayAdd(pass, r);
+      cupsArrayAdd(resolvers, r);
+
+      for (attr = ippFirstAttribute(r->collection);
+           attr;
+           attr = ippNextAttribute(r->collection))
+      {
+        if (new_option && !strcmp(attr->name, new_option))
+          continue;                    /* Ignore this if we just changed it */
+
+        if (ippAttributeString(attr, value, sizeof(value)) >= sizeof(value))
+          continue;                    /* Ignore if the value is too long */
+
+        if ((test = cups_test_constraints(dinfo, attr->name, value, num_myres,
+                                          myres, NULL, NULL)) == NULL)
+        {
+         /*
+          * That worked, flag it...
+          */
+
+          changed = 1;
+        }
+        else
+          cupsArrayDelete(test);
+
+       /*
+       * Add the option/value from the resolver regardless of whether it
+       * worked; this makes sure that we can cascade several changes to
+       * make things resolve...
+       */
+
+       num_myres = cupsAddOption(attr->name, value, num_myres, &myres);
+      }
+    }
+
+    if (!changed)
+    {
+      DEBUG_puts("1cupsCopyDestConflicts: Unable to resolve constraints.");
+      have_conflicts = -1;
+      goto cleanup;
+    }
+
+    cupsArrayClear(pass);
+
+    cupsArrayDelete(active);
+    active = NULL;
+  }
+
+  if (tries >= 0)
+  {
+    DEBUG_puts("1cupsCopyDestConflicts: Unable to resolve after 100 tries.");
+    have_conflicts = -1;
+    goto cleanup;
+  }
+
+ /*
+  * Copy resolved options as needed...
+  */
+
+  if (num_resolved)
+  {
+    for (i = num_myres, myoption = myres; i > 0; i --, myoption ++)
+    {
+      if ((myvalue = cupsGetOption(myoption->name, num_options,
+                                   options)) == NULL ||
+          strcmp(myvalue, myoption->value))
+      {
+        if (new_option && !strcmp(new_option, myoption->name) &&
+            new_value && !strcmp(new_value, myoption->value))
+          continue;
+
+        *num_resolved = cupsAddOption(myoption->name, myoption->value,
+                                      *num_resolved, resolved);
+      }
+    }
+  }
+
+ /*
+  * Clean up...
+  */
+
+  cleanup:
+
+  cupsArrayDelete(active);
+  cupsArrayDelete(pass);
+  cupsArrayDelete(resolvers);
+
+  if (num_resolved)
+  {
+   /*
+    * Free shadow copy of options...
+    */
+
+    cupsFreeOptions(num_myres, myres);
+  }
+
+  if (num_conflicts)
+  {
+   /*
+    * Return conflicting options to caller...
+    */
+
+    *num_conflicts = num_myconf;
+    *conflicts     = myconf;
+  }
+  else
+  {
+   /*
+    * Free conflicting options...
+    */
+
+    cupsFreeOptions(num_myconf, myconf);
+  }
+
+  return (have_conflicts);
 }
 
 
@@ -319,6 +573,9 @@ cupsCopyDestInfo(
   cups_dinfo_t *dinfo;                 /* Destination information */
   ipp_t                *request,               /* Get-Printer-Attributes request */
                *response;              /* Supported attributes */
+  int          tries,                  /* Number of tries so far */
+               delay,                  /* Current retry delay */
+               prev_delay;             /* Next retry delay */
   const char   *uri;                   /* Printer URI */
   char         resource[1024];         /* Resource path */
   int          version;                /* IPP version */
@@ -352,7 +609,10 @@ cupsCopyDestInfo(
   * Get the supported attributes...
   */
 
-  version = 20;
+  delay      = 1;
+  prev_delay = 1;
+  tries      = 0;
+  version    = 20;
 
   do
   {
@@ -383,11 +643,22 @@ cupsCopyDestInfo(
 
       if (status == IPP_VERSION_NOT_SUPPORTED && version > 11)
         version = 11;
+      else if (status == IPP_PRINTER_BUSY)
+      {
+        sleep(delay);
+
+        delay = _cupsNextDelay(delay, &prev_delay);
+      }
       else
         return (NULL);
     }
+
+    tries ++;
   }
-  while (!response);
+  while (!response && tries < 10);
+
+  if (!response)
+    return (NULL);
 
  /*
   * Allocate a cups_dinfo_t structure and return it...
@@ -429,14 +700,15 @@ cupsFreeDestInfo(cups_dinfo_t *dinfo)     /* I - Destination information */
 
   _cupsStrFree(dinfo->resource);
 
-  ippDelete(dinfo->attrs);
-
   cupsArrayDelete(dinfo->constraints);
+  cupsArrayDelete(dinfo->resolvers);
 
   cupsArrayDelete(dinfo->localizations);
 
   cupsArrayDelete(dinfo->media_db);
 
+  ippDelete(dinfo->attrs);
+
   free(dinfo);
 }
 
@@ -576,6 +848,46 @@ cupsGetDestMediaBySize(
 }
 
 
+/*
+ * 'cups_add_dconstres()' - Add a constraint or resolver to an array.
+ */
+
+static void
+cups_add_dconstres(
+    cups_array_t *a,                   /* I - Array */
+    ipp_t        *collection)          /* I - Collection value */
+{
+  ipp_attribute_t      *attr;          /* Attribute */
+  _cups_dconstres_t    *temp;          /* Current constraint/resolver */
+
+
+  if ((attr = ippFindAttribute(collection, "resolver-name",
+                               IPP_TAG_NAME)) == NULL)
+    return;
+
+  if ((temp = calloc(1, sizeof(_cups_dconstres_t))) == NULL)
+    return;
+
+  temp->name       = attr->values[0].string.text;
+  temp->collection = collection;
+
+  cupsArrayAdd(a, temp);
+}
+
+
+/*
+ * 'cups_compare_dconstres()' - Compare to resolver entries.
+ */
+
+static int                             /* O - Result of comparison */
+cups_compare_dconstres(
+    _cups_dconstres_t *a,              /* I - First resolver */
+    _cups_dconstres_t *b)              /* I - Second resolver */
+{
+  return (strcmp(a->name, b->name));
+}
+
+
 /*
  * 'cups_compare_media_db()' - Compare two media entries.
  */
@@ -633,6 +945,93 @@ cups_copy_media_db(
 }
 
 
+/*
+ * 'cups_create_constraints()' - Create the constraints and resolvers arrays.
+ */
+
+static void
+cups_create_constraints(
+    cups_dinfo_t *dinfo)               /* I - Destination information */
+{
+  int                  i;              /* Looping var */
+  ipp_attribute_t      *attr;          /* Attribute */
+  _ipp_value_t         *val;           /* Current value */
+
+
+  dinfo->constraints = cupsArrayNew3(NULL, NULL, NULL, 0, NULL,
+                                     (cups_afree_func_t)free);
+  dinfo->resolvers   = cupsArrayNew3((cups_array_func_t)cups_compare_dconstres,
+                                    NULL, NULL, 0, NULL,
+                                     (cups_afree_func_t)free);
+
+  if ((attr = ippFindAttribute(dinfo->attrs, "job-constraints-supported",
+                              IPP_TAG_BEGIN_COLLECTION)) != NULL)
+  {
+    for (i = attr->num_values, val = attr->values; i > 0; i --, val ++)
+      cups_add_dconstres(dinfo->constraints, val->collection);
+  }
+
+  if ((attr = ippFindAttribute(dinfo->attrs, "job-resolvers-supported",
+                              IPP_TAG_BEGIN_COLLECTION)) != NULL)
+  {
+    for (i = attr->num_values, val = attr->values; i > 0; i --, val ++)
+      cups_add_dconstres(dinfo->resolvers, val->collection);
+  }
+}
+
+
+/*
+ * 'cups_create_defaults()' - Create the -default option array.
+ *
+ * TODO: Need to support collection defaults...
+ */
+
+static void
+cups_create_defaults(
+    cups_dinfo_t *dinfo)               /* I - Destination information */
+{
+  ipp_attribute_t      *attr;          /* Current attribute */
+  char                 name[IPP_MAX_NAME + 1],
+                                       /* Current name */
+                       *nameptr,       /* Pointer into current name */
+                       value[2048];    /* Current value */
+
+
+ /*
+  * Iterate through the printer attributes looking for xxx-default and adding
+  * xxx=value to the defaults option array.
+  */
+
+  for (attr = ippFirstAttribute(dinfo->attrs);
+       attr;
+       attr = ippNextAttribute(dinfo->attrs))
+  {
+    if (!attr->name || attr->group_tag != IPP_TAG_PRINTER)
+      continue;
+
+    if (attr->value_tag == IPP_TAG_BEGIN_COLLECTION)
+      continue;                                /* TODO: STR #4096 */
+
+    if ((nameptr = attr->name + strlen(attr->name) - 8) <= attr->name ||
+        strcmp(nameptr, "-default"))
+      continue;
+
+    strlcpy(name, attr->name, sizeof(name));
+    if ((nameptr = name + strlen(name) - 8) <= name ||
+        strcmp(nameptr, "-default"))
+      continue;
+
+    *nameptr = '\0';
+
+    if (ippAttributeString(attr, value, sizeof(value)) >= sizeof(value))
+      continue;
+
+    dinfo->num_defaults = cupsAddOption(name, value, dinfo->num_defaults,
+                                        &dinfo->defaults);
+  }
+}
+
+
 /*
  * 'cups_create_media_db()' - Create the media database.
  */
@@ -1159,6 +1558,208 @@ cups_is_close_media_db(
 }
 
 
+/*
+ * 'cups_test_constraints()' - Test constraints.
+ *
+ * TODO: STR #4096 - Need to properly support media-col contraints...
+ */
+
+static cups_array_t *                  /* O - Active constraints */
+cups_test_constraints(
+    cups_dinfo_t  *dinfo,              /* I - Destination information */
+    const char    *new_option,         /* I - Newly selected option */
+    const char    *new_value,          /* I - Newly selected value */
+    int           num_options,         /* I - Number of options */
+    cups_option_t *options,            /* I - Options */
+    int           *num_conflicts,      /* O - Number of conflicting options */
+    cups_option_t **conflicts)         /* O - Conflicting options */
+{
+  int                  i,              /* Looping var */
+                       match;          /* Value matches? */
+  int                  num_matching;   /* Number of matching options */
+  cups_option_t                *matching;      /* Matching options */
+  _cups_dconstres_t    *c;             /* Current constraint */
+  cups_array_t         *active = NULL; /* Active constraints */
+  ipp_attribute_t      *attr;          /* Current attribute */
+  _ipp_value_t         *attrval;       /* Current attribute value */
+  const char           *value;         /* Current value */
+  char                 temp[1024];     /* Temporary string */
+  int                  int_value;      /* Integer value */
+  int                  xres_value,     /* Horizontal resolution */
+                       yres_value;     /* Vertical resolution */
+  ipp_res_t            units_value;    /* Resolution units */
+
+
+  for (c = (_cups_dconstres_t *)cupsArrayFirst(dinfo->constraints);
+       c;
+       c = (_cups_dconstres_t *)cupsArrayNext(dinfo->constraints))
+  {
+    num_matching = 0;
+    matching     = NULL;
+
+    for (attr = ippFirstAttribute(c->collection);
+         attr;
+         attr = ippNextAttribute(c->collection))
+    {
+      if (attr->value_tag == IPP_TAG_BEGIN_COLLECTION)
+        break;                         /* TODO: STR #4096 */
+
+     /*
+      * Get the value for the current attribute in the constraint...
+      */
+
+      if (new_option && new_value && !strcmp(attr->name, new_option))
+        value = new_value;
+      else if ((value = cupsGetOption(attr->name, num_options,
+                                      options)) == NULL)
+        value = cupsGetOption(attr->name, dinfo->num_defaults, dinfo->defaults);
+
+      if (!value)
+      {
+       /*
+        * Not set so this constraint does not apply...
+        */
+
+        break;
+      }
+
+      match = 0;
+
+      switch (attr->value_tag)
+      {
+        case IPP_TAG_INTEGER :
+        case IPP_TAG_ENUM :
+           int_value = atoi(value);
+
+           for (i = attr->num_values, attrval = attr->values;
+                i > 0;
+                i --, attrval ++)
+           {
+             if (attrval->integer == int_value)
+             {
+               match = 1;
+               break;
+             }
+            }
+            break;
+
+        case IPP_TAG_BOOLEAN :
+           int_value = !strcmp(value, "true");
+
+           for (i = attr->num_values, attrval = attr->values;
+                i > 0;
+                i --, attrval ++)
+           {
+             if (attrval->boolean == int_value)
+             {
+               match = 1;
+               break;
+             }
+            }
+            break;
+
+        case IPP_TAG_RANGE :
+           int_value = atoi(value);
+
+           for (i = attr->num_values, attrval = attr->values;
+                i > 0;
+                i --, attrval ++)
+           {
+             if (int_value >= attrval->range.lower &&
+                 int_value <= attrval->range.upper)
+             {
+               match = 1;
+               break;
+             }
+            }
+            break;
+
+        case IPP_TAG_RESOLUTION :
+           if (sscanf(value, "%dx%d%15s", &xres_value, &yres_value, temp) != 3)
+           {
+             if (sscanf(value, "%d%15s", &xres_value, temp) != 2)
+               break;
+
+             yres_value = xres_value;
+           }
+
+           if (!strcmp(temp, "dpi"))
+             units_value = IPP_RES_PER_INCH;
+           else if (!strcmp(temp, "dpc") || !strcmp(temp, "dpcm"))
+             units_value = IPP_RES_PER_CM;
+           else
+             break;
+
+           for (i = attr->num_values, attrval = attr->values;
+                i > 0;
+                i --, attrval ++)
+           {
+             if (attrval->resolution.xres == xres_value &&
+                 attrval->resolution.yres == yres_value &&
+                 attrval->resolution.units == units_value)
+             {
+               match = 1;
+               break;
+             }
+           }
+            break;
+
+       case IPP_TAG_TEXT :
+       case IPP_TAG_NAME :
+       case IPP_TAG_KEYWORD :
+       case IPP_TAG_CHARSET :
+       case IPP_TAG_URI :
+       case IPP_TAG_URISCHEME :
+       case IPP_TAG_MIMETYPE :
+       case IPP_TAG_LANGUAGE :
+       case IPP_TAG_TEXTLANG :
+       case IPP_TAG_NAMELANG :
+           for (i = attr->num_values, attrval = attr->values;
+                i > 0;
+                i --, attrval ++)
+           {
+             if (!strcmp(attrval->string.text, value))
+             {
+               match = 1;
+               break;
+             }
+            }
+           break;
+
+        default :
+            break;
+      }
+
+      if (!match)
+        break;
+
+      num_matching = cupsAddOption(attr->name, value, num_matching, &matching);
+    }
+
+    if (!attr)
+    {
+      if (!active)
+        active = cupsArrayNew(NULL, NULL);
+
+      cupsArrayAdd(active, c);
+
+      if (num_conflicts && conflicts)
+      {
+        cups_option_t  *moption;       /* Matching option */
+
+        for (i = num_matching, moption = matching; i > 0; i --, moption ++)
+          *num_conflicts = cupsAddOption(moption->name, moption->value,
+                                        *num_conflicts, conflicts);
+      }
+    }
+
+    cupsFreeOptions(num_matching, matching);
+  }
+
+  return (active);
+}
+
+
 /*
  * End of "$Id$".
  */
index ee9d57208bc0d4edb5944c008285e45d82e27ea2..3bc89d5da86800611f2d43f68bd03d3c45092529 100644 (file)
  *   cups_block_cb()               - Enumeration callback for block API.
  *   cups_compare_dests()          - Compare two destinations.
  *   cups_dnssd_browse_cb()        - Browse for printers.
+ *   cups_dnssd_browse_cb()        - Browse for printers.
+ *   cups_dnssd_client_cb()        - Avahi client callback function.
  *   cups_dnssd_compare_device()    - Compare two devices.
  *   cups_dnssd_free_device()      - Free the memory used by a device.
  *   cups_dnssd_get_device()       - Lookup a device and create it as needed.
  *   cups_dnssd_local_cb()         - Browse for local printers.
+ *   cups_dnssd_poll_cb()          - Wait for input on the specified file
+ *                                   descriptors.
  *   cups_dnssd_query_cb()         - Process query data.
- *   cups_dnssd_resolve()           - Resolve a Bonjour printer URI.
- *   cups_dnssd_resolve_cb()        - See if we should continue resolving.
+ *   cups_dnssd_resolve()          - Resolve a Bonjour printer URI.
+ *   cups_dnssd_resolve_cb()       - See if we should continue resolving.
  *   cups_dnssd_unquote()          - Unquote a name string.
  *   cups_find_dest()              - Find a destination using a binary search.
  *   cups_get_default()            - Get the default destination from an
 #  include <dns_sd.h>
 #endif /* HAVE_DNSSD */
 
+#ifdef HAVE_AVAHI
+#  include <avahi-client/client.h>
+#  include <avahi-client/lookup.h>
+#  include <avahi-common/simple-watch.h>
+#  include <avahi-common/domain.h>
+#  include <avahi-common/error.h>
+#  include <avahi-common/malloc.h>
+#define kDNSServiceMaxDomainName AVAHI_DOMAIN_NAME_MAX
+#endif /* HAVE_AVAHI */
+
 
 /*
  * Constants...
  * Types...
  */
 
-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
 typedef enum _cups_dnssd_state_e       /* Enumerated device state */
 {
   _CUPS_DNSSD_NEW,
@@ -125,12 +139,19 @@ typedef enum _cups_dnssd_state_e  /* Enumerated device state */
   _CUPS_DNSSD_PENDING,
   _CUPS_DNSSD_ACTIVE,
   _CUPS_DNSSD_LOCAL,
+  _CUPS_DNSSD_INCOMPATIBLE,
   _CUPS_DNSSD_ERROR
 } _cups_dnssd_state_t;
 
 typedef struct _cups_dnssd_data_s      /* Enumeration data */
 {
+#  ifdef HAVE_DNSSD
   DNSServiceRef                main_ref;       /* Main service reference */
+#  else /* HAVE_AVAHI */
+  AvahiSimplePoll      *simple_poll;   /* Polling interface */
+  AvahiClient          *client;        /* Client information */
+  int                  got_data;       /* Did we get data? */
+#  endif /* HAVE_DNSSD */
   cups_dest_cb_t       cb;             /* Callback */
   void                 *user_data;     /* User data pointer */
   cups_ptype_t         type,           /* Printer type filter */
@@ -141,7 +162,11 @@ typedef struct _cups_dnssd_data_s  /* Enumeration data */
 typedef struct _cups_dnssd_device_s    /* Enumerated device */
 {
   _cups_dnssd_state_t  state;          /* State of device listing */
+#  ifdef HAVE_DNSSD
   DNSServiceRef                ref;            /* Service reference for query */
+#  else /* HAVE_AVAHI */
+  AvahiRecordBrowser   *ref;           /* Browser for query */
+#  endif /* HAVE_DNSSD */
   char                 *domain,        /* Domain name */
                        *fullName,      /* Full name */
                        *regtype;       /* Registration type */
@@ -165,8 +190,8 @@ typedef struct _cups_dnssd_resolve_s        /* Data for resolving URI */
 static CFArrayRef      appleCopyLocations(void);
 static CFStringRef     appleCopyNetwork(void);
 static char            *appleGetPaperSize(char *name, int namesize);
-static CFStringRef     appleGetPrinter(CFArrayRef locations, CFStringRef network,
-                                       CFIndex *locindex);
+static CFStringRef     appleGetPrinter(CFArrayRef locations,
+                                       CFStringRef network, CFIndex *locindex);
 #endif /* __APPLE__ */
 static cups_dest_t     *cups_add_dest(const char *name, const char *instance,
                                       int *num_dests, cups_dest_t **dests);
@@ -175,7 +200,8 @@ static int          cups_block_cb(cups_dest_block_t block, unsigned flags,
                                      cups_dest_t *dest);
 #endif /* __BLOCKS__ */
 static int             cups_compare_dests(cups_dest_t *a, cups_dest_t *b);
-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
+#  ifdef HAVE_DNSSD
 static void            cups_dnssd_browse_cb(DNSServiceRef sdRef,
                                             DNSServiceFlags flags,
                                             uint32_t interfaceIndex,
@@ -184,6 +210,20 @@ static void                cups_dnssd_browse_cb(DNSServiceRef sdRef,
                                             const char *regtype,
                                             const char *replyDomain,
                                             void *context);
+#  else /* HAVE_AVAHI */
+static void            cups_dnssd_browse_cb(AvahiServiceBrowser *browser,
+                                            AvahiIfIndex interface,
+                                            AvahiProtocol protocol,
+                                            AvahiBrowserEvent event,
+                                            const char *serviceName,
+                                            const char *regtype,
+                                            const char *replyDomain,
+                                            AvahiLookupResultFlags flags,
+                                            void *context);
+static void            cups_dnssd_client_cb(AvahiClient *client,
+                                            AvahiClientState state,
+                                            void *context);
+#  endif /* HAVE_DNSSD */
 static int             cups_dnssd_compare_devices(_cups_dnssd_device_t *a,
                                                   _cups_dnssd_device_t *b);
 static void            cups_dnssd_free_device(_cups_dnssd_device_t *device,
@@ -193,6 +233,7 @@ static _cups_dnssd_device_t *
                                              const char *serviceName,
                                              const char *regtype,
                                              const char *replyDomain);
+#  ifdef HAVE_DNSSD
 static void            cups_dnssd_local_cb(DNSServiceRef sdRef,
                                            DNSServiceFlags flags,
                                            uint32_t interfaceIndex,
@@ -209,13 +250,27 @@ static void               cups_dnssd_query_cb(DNSServiceRef sdRef,
                                            uint16_t rrtype, uint16_t rrclass,
                                            uint16_t rdlen, const void *rdata,
                                            uint32_t ttl, void *context);
+#  else /* HAVE_AVAHI */
+static int             cups_dnssd_poll_cb(struct pollfd *pollfds,
+                                          unsigned int num_pollfds,
+                                          int timeout, void *context);
+static void            cups_dnssd_query_cb(AvahiRecordBrowser *browser,
+                                           AvahiIfIndex interface,
+                                           AvahiProtocol protocol,
+                                           AvahiBrowserEvent event,
+                                           const char *name, uint16_t rrclass,
+                                           uint16_t rrtype, const void *rdata,
+                                           size_t rdlen,
+                                           AvahiLookupResultFlags flags,
+                                           void *context);
+#  endif /* HAVE_DNSSD */
 static const char      *cups_dnssd_resolve(cups_dest_t *dest, const char *uri,
                                            int msec, int *cancel,
                                            cups_dest_cb_t cb, void *user_data);
 static int             cups_dnssd_resolve_cb(void *context);
 static void            cups_dnssd_unquote(char *dst, const char *src,
                                           size_t dstsize);
-#endif /* HAVE_DNSSD */
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
 static int             cups_find_dest(const char *name, const char *instance,
                                       int num_dests, cups_dest_t *dests, int prev,
                                       int *rdiff);
@@ -605,14 +660,14 @@ cupsConnectDest(
     return (NULL);
   }
 
-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
   if (strstr(uri, "._tcp"))
   {
     if ((uri = cups_dnssd_resolve(dest, uri, msec, cancel, cb,
                                   user_data)) == NULL)
       return (NULL);
   }
-#endif /* HAVE_DNSSD */
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
 
   if (httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme, sizeof(scheme),
                       userpass, sizeof(userpass), hostname, sizeof(hostname),
@@ -834,27 +889,34 @@ cupsEnumDests(
                        num_dests;      /* Number of destinations */
   cups_dest_t          *dests = NULL,  /* Destinations */
                        *dest;          /* Current destination */
-#ifdef HAVE_DNSSD
-  int                  nfds,           /* Number of files responded */
-                       count,          /* Number of queries started */
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
+  int                  count,          /* Number of queries started */
                        remaining;      /* Remainder of timeout */
   _cups_dnssd_data_t   data;           /* Data for callback */
   _cups_dnssd_device_t *device;        /* Current device */
-  int                  main_fd;        /* File descriptor for lookups */
+#  ifdef HAVE_DNSSD
+  int                  nfds,           /* Number of files responded */
+                       main_fd;        /* File descriptor for lookups */
   DNSServiceRef                ipp_ref,        /* IPP browser */
                        local_ipp_ref;  /* Local IPP browser */
-#  ifdef HAVE_SSL
+#    ifdef HAVE_SSL
   DNSServiceRef                ipps_ref,       /* IPPS browser */
                        local_ipps_ref; /* Local IPPS browser */
-#  endif /* HAVE_SSL */
-#  ifdef HAVE_POLL
+#    endif /* HAVE_SSL */
+#    ifdef HAVE_POLL
   struct pollfd                pfd;            /* Polling data */
-#  else
+#    else
   fd_set               input;          /* Input set for select() */
   struct timeval       timeout;        /* Timeout for select() */
-#  endif /* HAVE_POLL */
-#endif /* HAVE_DNSSD */
-
+#    endif /* HAVE_POLL */
+#  else /* HAVE_AVAHI */
+  int                  error;          /* Error value */
+  AvahiServiceBrowser  *ipp_ref;       /* IPP browser */
+#    ifdef HAVE_SSL
+  AvahiServiceBrowser  *ipps_ref;      /* IPPS browser */
+#    endif /* HAVE_SSL */
+#  endif /* HAVE_DNSSD */
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
 
  /*
   * Range check input...
@@ -884,7 +946,7 @@ cupsEnumDests(
   if (i > 0 || msec == 0)
     return (1);
 
-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
  /*
   * Get Bonjour-shared printers...
   */
@@ -895,6 +957,7 @@ cupsEnumDests(
                                NULL, NULL, 0, NULL,
                                (cups_afree_func_t)cups_dnssd_free_device);
 
+#  ifdef HAVE_DNSSD
   if (DNSServiceCreateConnection(&data.main_ref) != kDNSServiceErr_NoError)
     return (0);
 
@@ -902,27 +965,56 @@ cupsEnumDests(
 
   ipp_ref = data.main_ref;
   DNSServiceBrowse(&ipp_ref, kDNSServiceFlagsShareConnection, 0,
-                   "_ipp._tcp,_cups", NULL,
+                   "_ipp._tcp", NULL,
                    (DNSServiceBrowseReply)cups_dnssd_browse_cb, &data);
 
   local_ipp_ref = data.main_ref;
   DNSServiceBrowse(&local_ipp_ref, kDNSServiceFlagsShareConnection,
                    kDNSServiceInterfaceIndexLocalOnly,
-                   "_ipp._tcp,_cups", NULL,
+                   "_ipp._tcp", NULL,
                    (DNSServiceBrowseReply)cups_dnssd_local_cb, &data);
 
-#  ifdef HAVE_SSL
+#    ifdef HAVE_SSL
   ipps_ref = data.main_ref;
   DNSServiceBrowse(&ipps_ref, kDNSServiceFlagsShareConnection, 0,
-                   "_ipps._tcp,_cups", NULL,
+                   "_ipps._tcp", NULL,
                    (DNSServiceBrowseReply)cups_dnssd_browse_cb, &data);
 
   local_ipps_ref = data.main_ref;
   DNSServiceBrowse(&local_ipps_ref, kDNSServiceFlagsShareConnection,
                    kDNSServiceInterfaceIndexLocalOnly,
-                   "_ipps._tcp,_cups", NULL,
+                   "_ipps._tcp", NULL,
                    (DNSServiceBrowseReply)cups_dnssd_local_cb, &data);
-#  endif /* HAVE_SSL */
+#    endif /* HAVE_SSL */
+
+#  else /* HAVE_AVAHI */
+  if ((data.simple_poll = avahi_simple_poll_new()) == NULL)
+  {
+    DEBUG_puts("cupsEnumDests: Unable to create Avahi simple poll object.");
+    return (1);
+  }
+
+  avahi_simple_poll_set_func(data.simple_poll, cups_dnssd_poll_cb, &data);
+
+  data.client = avahi_client_new(avahi_simple_poll_get(data.simple_poll),
+                                0, cups_dnssd_client_cb, &data,
+                                &error);
+  if (!data.client)
+  {
+    DEBUG_puts("cupsEnumDests: Unable to create Avahi client.");
+    avahi_simple_poll_free(data.simple_poll);
+    return (1);
+  }
+
+  ipp_ref  = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC,
+                                      AVAHI_PROTO_UNSPEC, "_ipp._tcp", NULL,
+                                      0, cups_dnssd_browse_cb, &data);
+#    ifdef HAVE_SSL
+  ipps_ref = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC,
+                                      AVAHI_PROTO_UNSPEC, "_ipps._tcp", NULL,
+                                      0, cups_dnssd_browse_cb, &data);
+#    endif /* HAVE_SSL */
+#  endif /* HAVE_DNSSD */
 
   if (msec < 0)
     remaining = INT_MAX;
@@ -935,13 +1027,14 @@ cupsEnumDests(
     * Check for input...
     */
 
-#  ifdef HAVE_POLL
+#  ifdef HAVE_DNSSD
+#    ifdef HAVE_POLL
     pfd.fd     = main_fd;
     pfd.events = POLLIN;
 
     nfds = poll(&pfd, 1, remaining > 250 ? 250 : remaining);
 
-#  else
+#    else
     FD_ZERO(&input);
     FD_SET(main_fd, &input);
 
@@ -949,13 +1042,30 @@ cupsEnumDests(
     timeout.tv_usec = remaining > 250 ? 250000 : remaining * 1000;
 
     nfds = select(main_fd + 1, &input, NULL, NULL, &timeout);
-#  endif /* HAVE_POLL */
+#    endif /* HAVE_POLL */
 
     if (nfds > 0)
       DNSServiceProcessResult(data.main_ref);
     else if (nfds == 0)
       remaining -= 250;
 
+#  else /* HAVE_AVAHI */
+    data.got_data = 0;
+
+    if ((error = avahi_simple_poll_iterate(data.simple_poll, 250)) > 0)
+    {
+     /*
+      * We've been told to exit the loop.  Perhaps the connection to
+      * Avahi failed.
+      */
+
+      break;
+    }
+
+    if (!data.got_data)
+      remaining -= 250;
+#  endif /* HAVE_DNSSD */
+
     for (device = (_cups_dnssd_device_t *)cupsArrayFirst(data.devices),
              count = 0;
          device;
@@ -966,10 +1076,11 @@ cupsEnumDests(
 
       if (!device->ref && device->state == _CUPS_DNSSD_NEW)
       {
-        device->ref = data.main_ref;
-
        DEBUG_printf(("1cupsEnumDests: Querying '%s'.", device->fullName));
 
+#  ifdef HAVE_DNSSD
+        device->ref = data.main_ref;
+
        if (DNSServiceQueryRecord(&(device->ref),
                                  kDNSServiceFlagsShareConnection,
                                  0, device->fullName,
@@ -987,14 +1098,39 @@ cupsEnumDests(
 
          DEBUG_puts("1cupsEnumDests: Query failed.");
        }
+
+#  else /* HAVE_AVAHI */
+       if ((device->ref = avahi_record_browser_new(data.client,
+                                                   AVAHI_IF_UNSPEC,
+                                                   AVAHI_PROTO_UNSPEC,
+                                                   device->fullName,
+                                                   AVAHI_DNS_CLASS_IN,
+                                                   AVAHI_DNS_TYPE_TXT,
+                                                   0,
+                                                   cups_dnssd_query_cb,
+                                                   &data)) != NULL)
+        {
+         count ++;
+       }
+       else
+       {
+         device->state = _CUPS_DNSSD_ERROR;
+
+         DEBUG_printf(("1cupsEnumDests: Query failed: %s",
+                       avahi_strerror(avahi_client_errno(data.client))));
+       }
+#  endif /* HAVE_DNSSD */
       }
       else if (device->ref && device->state == _CUPS_DNSSD_PENDING)
       {
-       if (!(*cb)(user_data, CUPS_DEST_FLAGS_NONE, &device->dest))
-       {
-         remaining = -1;
-         break;
-       }
+        if ((device->type & mask) == type)
+        {
+         if (!(*cb)(user_data, CUPS_DEST_FLAGS_NONE, &device->dest))
+         {
+           remaining = -1;
+           break;
+         }
+        }
 
         device->state = _CUPS_DNSSD_ACTIVE;
       }
@@ -1003,16 +1139,27 @@ cupsEnumDests(
 
   cupsArrayDelete(data.devices);
 
+#  ifdef HAVE_DNSSD
   DNSServiceRefDeallocate(ipp_ref);
   DNSServiceRefDeallocate(local_ipp_ref);
 
-#  ifdef HAVE_SSL
+#    ifdef HAVE_SSL
   DNSServiceRefDeallocate(ipp_ref);
   DNSServiceRefDeallocate(local_ipp_ref);
-#  endif /* HAVE_SSL */
+#    endif /* HAVE_SSL */
 
   DNSServiceRefDeallocate(data.main_ref);
-#endif /* HAVE_DNSSD */
+
+#  else /* HAVE_AVAHI */
+  avahi_service_browser_free(ipp_ref);
+#    ifdef HAVE_SSL
+  avahi_service_browser_free(ipps_ref);
+#    endif /* HAVE_SSL */
+
+  avahi_client_free(data.client);
+  avahi_simple_poll_free(data.simple_poll);
+#  endif /* HAVE_DNSSD */
+#endif /* HAVE_DNSSD || HAVE_DNSSD */
 
   return (1);
 }
@@ -2473,7 +2620,8 @@ cups_compare_dests(cups_dest_t *a,        /* I - First destination */
 }
 
 
-#ifdef HAVE_DNSSD
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
+#  ifdef HAVE_DNSSD
 /*
  * 'cups_dnssd_browse_cb()' - Browse for printers.
  */
@@ -2514,6 +2662,102 @@ cups_dnssd_browse_cb(
 }
 
 
+#  else /* HAVE_AVAHI */
+/*
+ * 'cups_dnssd_browse_cb()' - Browse for printers.
+ */
+
+static void
+cups_dnssd_browse_cb(
+    AvahiServiceBrowser    *browser,   /* I - Browser */
+    AvahiIfIndex           interface,  /* I - Interface index (unused) */
+    AvahiProtocol          protocol,   /* I - Network protocol (unused) */
+    AvahiBrowserEvent      event,      /* I - What happened */
+    const char             *name,      /* I - Service name */
+    const char             *type,      /* I - Registration type */
+    const char             *domain,    /* I - Domain */
+    AvahiLookupResultFlags flags,      /* I - Flags */
+    void                   *context)   /* I - Devices array */
+{
+  AvahiClient          *client = avahi_service_browser_get_client(browser);
+                                       /* Client information */
+  _cups_dnssd_data_t   *data = (_cups_dnssd_data_t *)context;
+                                       /* Enumeration data */
+
+
+  (void)interface;
+  (void)protocol;
+  (void)context;
+
+  switch (event)
+  {
+    case AVAHI_BROWSER_FAILURE:
+       DEBUG_printf(("cups_dnssd_browse_cb: %s",
+                     avahi_strerror(avahi_client_errno(client))));
+       avahi_simple_poll_quit(data->simple_poll);
+       break;
+
+    case AVAHI_BROWSER_NEW:
+       /*
+       * This object is new on the network.
+       */
+
+       if (flags & AVAHI_LOOKUP_RESULT_LOCAL)
+       {
+        /*
+         * This comes from the local machine so ignore it.
+         */
+
+         DEBUG_printf(("cups_dnssd_browse_cb: Ignoring local service \"%s\".",
+                       name));
+       }
+       else
+       {
+        /*
+         * Create a device entry for it if it doesn't yet exist.
+         */
+
+         cups_dnssd_get_device(data, name, type, domain);
+       }
+       break;
+
+    case AVAHI_BROWSER_REMOVE:
+    case AVAHI_BROWSER_ALL_FOR_NOW:
+    case AVAHI_BROWSER_CACHE_EXHAUSTED:
+        break;
+  }
+}
+
+
+/*
+ * 'cups_dnssd_client_cb()' - Avahi client callback function.
+ */
+
+static void
+cups_dnssd_client_cb(
+    AvahiClient      *client,          /* I - Client information (unused) */
+    AvahiClientState state,            /* I - Current state */
+    void             *context)         /* I - User data (unused) */
+{
+  _cups_dnssd_data_t   *data = (_cups_dnssd_data_t *)context;
+                                       /* Enumeration data */
+
+
+  (void)client;
+
+ /*
+  * If the connection drops, quit.
+  */
+
+  if (state == AVAHI_CLIENT_FAILURE)
+  {
+    DEBUG_puts("cups_dnssd_client_cb: Avahi connection failed.");
+    avahi_simple_poll_quit(data->simple_poll);
+  }
+}
+#  endif /* HAVE_DNSSD */
+
+
 /*
  * 'cups_dnssd_compare_device()' - Compare two devices.
  */
@@ -2539,8 +2783,13 @@ cups_dnssd_free_device(
   DEBUG_printf(("5cups_dnssd_free_device(device=%p(%s), data=%p)", device,
                 device->dest.name, data));
 
+#  ifdef HAVE_DNSSD
   if (device->ref)
     DNSServiceRefDeallocate(device->ref);
+#  else /* HAVE_AVAHI */
+  if (device->ref)
+    avahi_record_browser_free(device->ref);
+#  endif /* HAVE_DNSSD */
 
   _cupsStrFree(device->domain);
   _cupsStrFree(device->fullName);
@@ -2650,14 +2899,25 @@ cups_dnssd_get_device(
   * Set the "full name" of this service, which is used for queries...
   */
 
+#  ifdef HAVE_DNSSD
   DNSServiceConstructFullName(fullName, device->dest.name, device->regtype,
                              device->domain);
+#  else /* HAVE_AVAHI */
+  avahi_service_name_join(fullName, kDNSServiceMaxDomainName, serviceName,
+                          regtype, replyDomain);
+#  endif /* HAVE_DNSSD */
+
   _cupsStrFree(device->fullName);
   device->fullName = _cupsStrAlloc(fullName);
 
   if (device->ref)
   {
+#  ifdef HAVE_DNSSD
     DNSServiceRefDeallocate(device->ref);
+#  else /* HAVE_AVAHI */
+    avahi_record_browser_free(device->ref);
+#  endif /* HAVE_DNSSD */
+
     device->ref = 0;
   }
 
@@ -2671,6 +2931,7 @@ cups_dnssd_get_device(
 }
 
 
+#  ifdef HAVE_DNSSD
 /*
  * 'cups_dnssd_local_cb()' - Browse for local printers.
  */
@@ -2728,12 +2989,51 @@ cups_dnssd_local_cb(
 
   device->state = _CUPS_DNSSD_LOCAL;
 }
+#  endif /* HAVE_DNSSD */
+
+
+#  ifdef HAVE_AVAHI
+/*
+ * 'cups_dnssd_poll_cb()' - Wait for input on the specified file descriptors.
+ *
+ * Note: This function is needed because avahi_simple_poll_iterate is broken
+ *       and always uses a timeout of 0 (!) milliseconds.
+ *       (Avahi Ticket #364)
+ */
+
+static int                             /* O - Number of file descriptors matching */
+cups_dnssd_poll_cb(
+    struct pollfd *pollfds,            /* I - File descriptors */
+    unsigned int  num_pollfds,         /* I - Number of file descriptors */
+    int           timeout,             /* I - Timeout in milliseconds (unused) */
+    void          *context)            /* I - User data (unused) */
+{
+  _cups_dnssd_data_t   *data = (_cups_dnssd_data_t *)context;
+                                       /* Enumeration data */
+  int                  val;            /* Return value */
+
+
+  (void)timeout;
+
+  val = poll(pollfds, num_pollfds, 250);
+
+  if (val < 0)
+  {
+    DEBUG_printf(("cups_dnssd_poll_cb: %s", strerror(errno)));
+  }
+  else if (val > 0)
+    data->got_data = 1;
+
+  return (val);
+}
+#  endif /* HAVE_AVAHI */
 
 
 /*
  * 'cups_dnssd_query_cb()' - Process query data.
  */
 
+#  ifdef HAVE_DNSSD
 static void
 cups_dnssd_query_cb(
     DNSServiceRef       sdRef,         /* I - Service reference */
@@ -2748,6 +3048,25 @@ cups_dnssd_query_cb(
     uint32_t            ttl,           /* I - Time-to-live */
     void                *context)      /* I - Enumeration data */
 {
+#  else /* HAVE_AVAHI */
+static void
+cups_dnssd_query_cb(
+    AvahiRecordBrowser     *browser,   /* I - Record browser */
+    AvahiIfIndex           interfaceIndex,
+                                       /* I - Interface index (unused) */
+    AvahiProtocol          protocol,   /* I - Network protocol (unused) */
+    AvahiBrowserEvent      event,      /* I - What happened? */
+    const char             *fullName,  /* I - Service name */
+    uint16_t               rrclass,    /* I - Record class */
+    uint16_t               rrtype,     /* I - Record type */
+    const void             *rdata,     /* I - TXT record */
+    size_t                 rdlen,      /* I - Length of TXT record */
+    AvahiLookupResultFlags flags,      /* I - Flags */
+    void                   *context)   /* I - Enumeration data */
+{
+  AvahiClient          *client = avahi_record_browser_get_client(browser);
+                                       /* Client information */
+#  endif /* HAVE_DNSSD */
   _cups_dnssd_data_t   *data = (_cups_dnssd_data_t *)context;
                                        /* Enumeration data */
   char                 name[1024],     /* Service name */
@@ -2756,6 +3075,7 @@ cups_dnssd_query_cb(
                        *device;        /* Device */
 
 
+#  ifdef HAVE_DNSSD
   DEBUG_printf(("5cups_dnssd_query_cb(sdRef=%p, flags=%x, "
                "interfaceIndex=%d, errorCode=%d, fullName=\"%s\", "
                "rrtype=%u, rrclass=%u, rdlen=%u, rdata=%p, ttl=%u, "
@@ -2769,6 +3089,27 @@ cups_dnssd_query_cb(
   if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd))
     return;
 
+#  else /* HAVE_AVAHI */
+  DEBUG_printf(("5cups_dnssd_query_cb(browser=%p, interfaceIndex=%d, "
+               "protocol=%d, event=%d, fullName=\"%s\", rrclass=%u, "
+               "rrtype=%u, rdata=%p, rdlen=%u, flags=%x, context=%p)",
+               browser, interfaceIndex, protocol, event, fullName, rrclass,
+               rrtype, rdata, (unsigned)rdlen, flags, context));
+
+ /*
+  * Only process "add" data...
+  */
+
+  if (event != AVAHI_BROWSER_NEW)
+  {
+    if (event == AVAHI_BROWSER_FAILURE)
+      DEBUG_printf(("cups_dnssd_query_cb: %s",
+                   avahi_strerror(avahi_client_errno(client))));
+
+    return;
+  }
+#  endif /* HAVE_DNSSD */
+
  /*
   * Lookup the service in the devices array.
   */
@@ -2783,8 +3124,7 @@ cups_dnssd_query_cb(
   if ((device = cupsArrayFind(data->devices, &dkey)) != NULL)
   {
    /*
-    * Found it, pull out the priority and make and model from the TXT
-    * record and save it...
+    * Found it, pull out the make and model from the TXT record and save it...
     */
 
     const uint8_t      *txt,           /* Pointer into data */
@@ -2798,6 +3138,10 @@ cups_dnssd_query_cb(
                        model[256],     /* Model */
                        uriname[1024],  /* Name for URI */
                        uri[1024];      /* Printer URI */
+    cups_ptype_t       type = CUPS_PRINTER_REMOTE | CUPS_PRINTER_BW;
+                                       /* Printer type */
+    int                        saw_printer_type = 0;
+                                       /* Did we see a printer-type key? */
 
     device->state     = _CUPS_DNSSD_PENDING;
     make_and_model[0] = '\0';
@@ -2871,18 +3215,102 @@ cups_dnssd_query_cb(
        if ((ptr = strchr(model, ',')) != NULL)
          *ptr = '\0';
       }
+      else if (!_cups_strcasecmp(key, "note"))
+        device->dest.num_options = cupsAddOption("printer-location", value,
+                                                device->dest.num_options,
+                                                &device->dest.options);
+      else if (!_cups_strcasecmp(key, "pdl"))
+      {
+       /*
+        * Look for PDF-capable printers; only PDF-capable printers are shown.
+        */
+
+        const char     *start, *next;  /* Pointer into value */
+        int            have_pdf = 0;   /* Have PDF? */
+
+        for (start = value; start && *start; start = next)
+        {
+          if (!_cups_strncasecmp(start, "application/pdf", 15) &&
+              (!start[15] || start[15] == ','))
+          {
+            have_pdf = 1;
+            break;
+          }
+
+          if ((next = strchr(start, ',')) != NULL)
+            next ++;
+        }
+
+        if (!have_pdf)
+          device->state = _CUPS_DNSSD_INCOMPATIBLE;
+      }
       else if (!_cups_strcasecmp(key, "printer-type"))
       {
-        device->dest.num_options = cupsAddOption("printer-type", value,
-                                                 device->dest.num_options,
-                                                 &device->dest.options);
+       /*
+        * Value is either NNNN or 0xXXXX
+        */
+
+       saw_printer_type = 1;
+        type             = strtol(value, NULL, 0);
+      }
+      else if (!saw_printer_type)
+      {
+       if (!_cups_strcasecmp(key, "air") &&
+                !_cups_strcasecmp(value, "t"))
+         type |= CUPS_PRINTER_AUTHENTICATED;
+       else if (!_cups_strcasecmp(key, "bind") &&
+                !_cups_strcasecmp(value, "t"))
+         type |= CUPS_PRINTER_BIND;
+       else if (!_cups_strcasecmp(key, "collate") &&
+                !_cups_strcasecmp(value, "t"))
+         type |= CUPS_PRINTER_COLLATE;
+       else if (!_cups_strcasecmp(key, "color") &&
+                !_cups_strcasecmp(value, "t"))
+         type |= CUPS_PRINTER_COLOR;
+       else if (!_cups_strcasecmp(key, "copies") &&
+                !_cups_strcasecmp(value, "t"))
+         type |= CUPS_PRINTER_COPIES;
+       else if (!_cups_strcasecmp(key, "duplex") &&
+                !_cups_strcasecmp(value, "t"))
+         type |= CUPS_PRINTER_DUPLEX;
+       else if (!_cups_strcasecmp(key, "fax") &&
+                !_cups_strcasecmp(value, "t"))
+         type |= CUPS_PRINTER_MFP;
+       else if (!_cups_strcasecmp(key, "papercustom") &&
+                !_cups_strcasecmp(value, "t"))
+         type |= CUPS_PRINTER_VARIABLE;
+       else if (!_cups_strcasecmp(key, "papermax"))
+       {
+         if (!_cups_strcasecmp(value, "legal-a4"))
+           type |= CUPS_PRINTER_SMALL;
+         else if (!_cups_strcasecmp(value, "isoc-a2"))
+           type |= CUPS_PRINTER_MEDIUM;
+         else if (!_cups_strcasecmp(value, ">isoc-a2"))
+           type |= CUPS_PRINTER_LARGE;
+       }
+       else if (!_cups_strcasecmp(key, "punch") &&
+                !_cups_strcasecmp(value, "t"))
+         type |= CUPS_PRINTER_PUNCH;
+       else if (!_cups_strcasecmp(key, "scan") &&
+                !_cups_strcasecmp(value, "t"))
+         type |= CUPS_PRINTER_MFP;
+       else if (!_cups_strcasecmp(key, "sort") &&
+                !_cups_strcasecmp(value, "t"))
+         type |= CUPS_PRINTER_SORT;
+       else if (!_cups_strcasecmp(key, "staple") &&
+                !_cups_strcasecmp(value, "t"))
+         type |= CUPS_PRINTER_STAPLE;
       }
     }
 
    /*
-    * Save the make-and-model...
+    * Save the printer-xxx values...
     */
 
+    device->dest.num_options = cupsAddOption("printer-info", name,
+                                            device->dest.num_options,
+                                            &device->dest.options);
+
     if (make_and_model[0])
     {
       strlcat(make_and_model, " ", sizeof(make_and_model));
@@ -2899,6 +3327,12 @@ cups_dnssd_query_cb(
                                               device->dest.num_options,
                                               &device->dest.options);
 
+    device->type = type;
+    snprintf(value, sizeof(value), "%u", type);
+    device->dest.num_options = cupsAddOption("printer-type", value,
+                                            device->dest.num_options,
+                                            &device->dest.options);
+
    /*
     * Save the URI...
     */
@@ -2906,7 +3340,7 @@ cups_dnssd_query_cb(
     cups_dnssd_unquote(uriname, device->fullName, sizeof(uriname));
     httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri),
                     !strcmp(device->regtype, "_ipps._tcp") ? "ipps" : "ipp",
-                    NULL, uriname, 0, "/cups");
+                    NULL, uriname, 0, saw_printer_type ? "/cups" : "/");
 
     DEBUG_printf(("6cups_dnssd_query: printer-uri-supported=\"%s\"", uri));
 
index 9e1ef660f45591327b93f7d28935d1d6973fded7..4b09d8eaceb108962f94b40de2cbecdcbf784bb5 100644 (file)
 #ifdef HAVE_RESOLV_H
 #  include <resolv.h>
 #endif /* HAVE_RESOLV_H */
-#ifdef HAVE_COREFOUNDATION
+#ifdef __APPLE__
 #  include <CoreFoundation/CoreFoundation.h>
-#endif /* HAVE_COREFOUNDATION */
-#ifdef HAVE_SYSTEMCONFIGURATION
 #  include <SystemConfiguration/SystemConfiguration.h>
-#endif /* HAVE_SYSTEMCONFIGURATION */
+#endif /* __APPLE__ */
 
 
 /*
index 945404cdd1d08bf481ee9e7f7b58205307671fdd..9957a16aeaec8cc54694ac336eef2eafa93d5d71 100644 (file)
@@ -2170,14 +2170,10 @@ httpRead2(http_t *http,                 /* I - Connection to server */
   {
     if (http->data_encoding == HTTP_ENCODE_CHUNKED)
       httpGets(len, sizeof(len), http);
-
-    if (http->data_encoding != HTTP_ENCODE_CHUNKED)
-    {
-      if (http->state == HTTP_POST_RECV)
-       http->state ++;
-      else
-       http->state = HTTP_WAITING;
-    }
+    else if (http->state == HTTP_POST_RECV)
+      http->state ++;
+    else
+      http->state = HTTP_WAITING;
   }
 
   return (bytes);
@@ -2356,6 +2352,23 @@ httpReconnect2(http_t *http,             /* I - Connection to server */
     http->fd = -1;
   }
 
+ /*
+  * Reset all state (except fields, which may be reused)...
+  */
+
+  http->state           = HTTP_WAITING;
+  http->status          = HTTP_CONTINUE;
+  http->version         = HTTP_1_1;
+  http->keep_alive      = HTTP_KEEPALIVE_OFF;
+  memset(&http->_hostaddr, 0, sizeof(http->_hostaddr));
+  http->data_encoding   = HTTP_ENCODE_LENGTH;
+  http->_data_remaining = 0;
+  http->used            = 0;
+  http->expect          = 0;
+  http->data_remaining  = 0;
+  http->hostaddr        = NULL;
+  http->wused           = 0;
+
  /*
   * Connect to the server...
   */
@@ -2394,8 +2407,6 @@ httpReconnect2(http_t *http,              /* I - Connection to server */
 
   http->hostaddr = &(addr->addr);
   http->error    = 0;
-  http->status   = HTTP_CONTINUE;
-  http->state    = HTTP_WAITING;
 
 #ifdef HAVE_SSL
   if (http->encryption == HTTP_ENCRYPT_ALWAYS)
@@ -3968,7 +3979,9 @@ http_setup_ssl(http_t *http)              /* I - Connection to server */
   http->tls = SSL_new(context);
   SSL_set_bio(http->tls, bio, bio);
 
+#   ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
   SSL_set_tlsext_host_name(http->tls, hostname);
+#   endif /* HAVE_SSL_SET_TLSEXT_HOST_NAME */
 
   if (SSL_connect(http->tls) != 1)
   {
index dd3e4e0d462ca5e20dc909c18f0413fe60b51978..0a1e31c5646c157ec03f36bad8017598cea7d707 100644 (file)
@@ -2577,7 +2577,7 @@ ippReadIO(void       *src,                /* I - Data source */
               */
 
              _cupsSetError(IPP_INTERNAL_ERROR, _("IPP extension tag larger than 0x7FFFFFFF."), 1);
-             DEBUG_printf(("1ippReadIO: bad name length %d.", n));
+             DEBUG_printf(("1ippReadIO: bad tag 0x%x.", tag));
              _cupsBufferRelease((char *)buffer);
              return (IPP_ERROR);
             }
@@ -2846,7 +2846,7 @@ ippReadIO(void       *src,                /* I - Data source */
                  else
                    _cupsSetError(IPP_INTERNAL_ERROR,
                                  _("IPP enum value not 4 bytes."), 1);
-                 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
+                 DEBUG_printf(("1ippReadIO: bad integer value length %d.", n));
                  _cupsBufferRelease((char *)buffer);
                  return (IPP_ERROR);
                }
@@ -2872,7 +2872,7 @@ ippReadIO(void       *src,                /* I - Data source */
                {
                  _cupsSetError(IPP_INTERNAL_ERROR, _("IPP boolean value not 1 byte."),
                                1);
-                 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
+                 DEBUG_printf(("1ippReadIO: bad boolean value length %d.", n));
                  _cupsBufferRelease((char *)buffer);
                  return (IPP_ERROR);
                }
@@ -2913,11 +2913,14 @@ ippReadIO(void       *src,              /* I - Data source */
            case IPP_TAG_CHARSET :
            case IPP_TAG_LANGUAGE :
            case IPP_TAG_MIMETYPE :
-               if ((*cb)(src, buffer, n) < n)
-               {
-                 DEBUG_puts("1ippReadIO: unable to read string value.");
-                 _cupsBufferRelease((char *)buffer);
-                 return (IPP_ERROR);
+               if (n > 0)
+               {
+                 if ((*cb)(src, buffer, n) < n)
+                 {
+                   DEBUG_puts("1ippReadIO: unable to read string value.");
+                   _cupsBufferRelease((char *)buffer);
+                   return (IPP_ERROR);
+                 }
                }
 
                buffer[n] = '\0';
@@ -2929,7 +2932,7 @@ ippReadIO(void       *src,                /* I - Data source */
                if (n != 11)
                {
                  _cupsSetError(IPP_INTERNAL_ERROR, _("IPP date value not 11 bytes."), 1);
-                 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
+                 DEBUG_printf(("1ippReadIO: bad date value length %d.", n));
                  _cupsBufferRelease((char *)buffer);
                  return (IPP_ERROR);
                }
@@ -2947,7 +2950,7 @@ ippReadIO(void       *src,                /* I - Data source */
                {
                  _cupsSetError(IPP_INTERNAL_ERROR,
                                _("IPP resolution value not 9 bytes."), 1);
-                 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
+                 DEBUG_printf(("1ippReadIO: bad resolution value length %d.", n));
                  _cupsBufferRelease((char *)buffer);
                  return (IPP_ERROR);
                }
@@ -2974,7 +2977,8 @@ ippReadIO(void       *src,                /* I - Data source */
                {
                  _cupsSetError(IPP_INTERNAL_ERROR,
                                _("IPP rangeOfInteger value not 8 bytes."), 1);
-                 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
+                 DEBUG_printf(("1ippReadIO: bad rangeOfInteger value length "
+                               "%d.", n));
                  _cupsBufferRelease((char *)buffer);
                  return (IPP_ERROR);
                }
@@ -3006,7 +3010,8 @@ ippReadIO(void       *src,                /* I - Data source */
                    _cupsSetError(IPP_INTERNAL_ERROR,
                                  _("IPP nameWithLanguage value less than "
                                    "minimum 4 bytes."), 1);
-                 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
+                 DEBUG_printf(("1ippReadIO: bad stringWithLanguage value "
+                               "length %d.", n));
                  _cupsBufferRelease((char *)buffer);
                  return (IPP_ERROR);
                }
@@ -3038,7 +3043,8 @@ ippReadIO(void       *src,                /* I - Data source */
                {
                  _cupsSetError(IPP_INTERNAL_ERROR,
                                _("IPP language length overflows value."), 1);
-                 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
+                 DEBUG_printf(("1ippReadIO: bad language value length %d.",
+                               n));
                  _cupsBufferRelease((char *)buffer);
                  return (IPP_ERROR);
                }
@@ -3055,7 +3061,7 @@ ippReadIO(void       *src,                /* I - Data source */
                {
                  _cupsSetError(IPP_INTERNAL_ERROR,
                                _("IPP string length overflows value."), 1);
-                 DEBUG_printf(("1ippReadIO: bad value length %d.", n));
+                 DEBUG_printf(("1ippReadIO: bad string value length %d.", n));
                  _cupsBufferRelease((char *)buffer);
                  return (IPP_ERROR);
                }
@@ -3110,7 +3116,15 @@ ippReadIO(void       *src,               /* I - Data source */
                * we need to carry over...
                */
 
-               if ((*cb)(src, buffer, n) < n)
+               if (n == 0)
+               {
+                 _cupsSetError(IPP_INTERNAL_ERROR,
+                               _("IPP memberName value is empty."), 1);
+                 DEBUG_puts("1ippReadIO: Empty member name value.");
+                 _cupsBufferRelease((char *)buffer);
+                 return (IPP_ERROR);
+               }
+               else if ((*cb)(src, buffer, n) < n)
                {
                  DEBUG_puts("1ippReadIO: Unable to read member name value.");
                  _cupsBufferRelease((char *)buffer);
@@ -5287,9 +5301,8 @@ ipp_read_http(http_t      *http,  /* I - Client connection */
               ipp_uchar_t *buffer,     /* O - Buffer for data */
              size_t      length)       /* I - Total length */
 {
-  int          tbytes,                 /* Total bytes read */
-               bytes;                  /* Bytes read this pass */
-  char         len[32];                /* Length string */
+  int  tbytes,                         /* Total bytes read */
+       bytes;                          /* Bytes read this pass */
 
 
   DEBUG_printf(("7ipp_read_http(http=%p, buffer=%p, length=%d)",
@@ -5309,87 +5322,36 @@ ipp_read_http(http_t      *http,        /* I - Client connection */
     if (http->state == HTTP_WAITING)
       break;
 
-    if (http->used > 0 && http->data_encoding == HTTP_ENCODE_LENGTH)
+    if (http->used == 0 && !http->blocking)
     {
      /*
-      * Do "fast read" from HTTP buffer directly...
+      * Wait up to 10 seconds for more data on non-blocking sockets...
       */
 
-      if (http->used > (int)(length - tbytes))
-        bytes = (int)(length - tbytes);
-      else
-        bytes = http->used;
-
-      if (bytes == 1)
-       buffer[0] = http->buffer[0];
-      else
-       memcpy(buffer, http->buffer, bytes);
-
-      http->used           -= bytes;
-      http->data_remaining -= bytes;
-
-      if (http->data_remaining <= INT_MAX)
-       http->_data_remaining = (int)http->data_remaining;
-      else
-       http->_data_remaining = INT_MAX;
-
-      if (http->used > 0)
-       memmove(http->buffer, http->buffer + bytes, http->used);
-
-      if (http->data_remaining == 0)
-      {
-       if (http->data_encoding == HTTP_ENCODE_CHUNKED)
-       {
-        /*
-         * Get the trailing CR LF after the chunk...
-         */
-
-         if (!httpGets(len, sizeof(len), http))
-           return (-1);
-       }
-
-       if (http->data_encoding != HTTP_ENCODE_CHUNKED)
-       {
-         if (http->state == HTTP_POST_RECV)
-           http->state ++;
-         else
-           http->state = HTTP_WAITING;
-       }
-      }
-    }
-    else
-    {
-      if (!http->blocking)
+      if (!httpWait(http, 10000))
       {
        /*
-        * Wait up to 10 seconds for more data on non-blocking sockets...
+       * Signal no data...
        */
 
-       if (!httpWait(http, 10000))
-       {
-        /*
-          * Signal no data...
-         */
-
-          bytes = -1;
-         break;
-       }
+       bytes = -1;
+       break;
       }
+    }
 
-      if ((bytes = httpRead2(http, (char *)buffer, length - tbytes)) < 0)
-      {
+    if ((bytes = httpRead2(http, (char *)buffer, length - tbytes)) < 0)
+    {
 #ifdef WIN32
-        break;
+      break;
 #else
-        if (errno != EAGAIN && errno != EINTR)
-         break;
+      if (errno != EAGAIN && errno != EINTR)
+       break;
 
-       bytes = 0;
+      bytes = 0;
 #endif /* WIN32 */
-      }
-      else if (bytes == 0)
-        break;
     }
+    else if (bytes == 0)
+      break;
   }
 
  /*
index 6a2a886b1320075edf232ea48eabfd917dc4642f..cf5b482b4357c7de2a653bd43cd90243e260129f 100644 (file)
@@ -71,6 +71,7 @@ extern const char     *_cupsLangString(cups_lang_t *lang,
 extern void            _cupsMessageFree(cups_array_t *a);
 extern cups_array_t    *_cupsMessageLoad(const char *filename, int unquote);
 extern const char      *_cupsMessageLookup(cups_array_t *a, const char *m);
+extern cups_array_t    *_cupsMessageNew(void *context);
 extern void            _cupsSetLocale(char *argv[]);
 
 
index 3e9db9ff80a903da4a87226480626de6dc776380..74af58932560afaefcc37424cfec59a38087a220 100644 (file)
  * Contents:
  *
  *   _cupsAppleLanguage()   - Get the Apple language identifier associated with
- *                            a locale ID.
+ *                           a locale ID.
  *   _cupsEncodingName()    - Return the character encoding name string for the
- *                            given encoding enumeration.
- *   cupsLangDefault()      - Return the default language.
- *   cupsLangEncoding()     - Return the character encoding (us-ascii, etc.) for
- *                            the given language.
- *   cupsLangFlush()        - Flush all language data out of the cache.
- *   cupsLangFree()         - Free language data.
- *   cupsLangGet()          - Get a language.
- *   _cupsLangString()      - Get a message string.
+ *                           given encoding enumeration.
+ *   cupsLangDefault()     - Return the default language.
+ *   cupsLangEncoding()     - Return the character encoding (us-ascii, etc.)
+ *                           for the given language.
+ *   cupsLangFlush()       - Flush all language data out of the cache.
+ *   cupsLangFree()        - Free language data.
+ *   cupsLangGet()         - Get a language.
+ *   _cupsLangString()     - Get a message string.
  *   _cupsMessageFree()     - Free a messages array.
  *   _cupsMessageLoad()     - Load a .po file into a messages array.
  *   _cupsMessageLookup()   - Lookup a message string.
+ *   _cupsMessageNew()     - Make a new message catalog array.
  *   appleLangDefault()     - Get the default locale string.
  *   appleMessageLoad()     - Load a message catalog from a localizable bundle.
  *   cups_cache_lookup()    - Lookup a language in the cache...
  *   cups_message_compare() - Compare two messages.
  *   cups_message_free()    - Free a message.
  *   cups_message_load()    - Load the message catalog for a language.
- *   cups_unquote()         - Unquote characters in strings...
+ *   cups_unquote()        - Unquote characters in strings...
  */
 
 /*
@@ -854,10 +855,7 @@ _cupsMessageLoad(const char *filename,     /* I - Message catalog to load */
   * Create an array to hold the messages...
   */
 
-  if ((a = cupsArrayNew3((cups_array_func_t)cups_message_compare, NULL,
-                         (cups_ahash_func_t)NULL, 0,
-                        (cups_acopy_func_t)NULL,
-                        (cups_afree_func_t)cups_message_free)) == NULL)
+  if ((a = _cupsMessageNew(NULL)) == NULL)
   {
     DEBUG_puts("5_cupsMessageLoad: Unable to allocate array!");
     return (NULL);
@@ -1140,6 +1138,20 @@ _cupsMessageLookup(cups_array_t *a,      /* I - Message array */
 }
 
 
+/*
+ * '_cupsMessageNew()' - Make a new message catalog array.
+ */
+
+cups_array_t *                         /* O - Array */
+_cupsMessageNew(void *context)         /* I - User data */
+{
+  return (cupsArrayNew3((cups_array_func_t)cups_message_compare, context,
+                        (cups_ahash_func_t)NULL, 0,
+                       (cups_acopy_func_t)NULL,
+                       (cups_afree_func_t)cups_message_free));
+}
+
+
 #ifdef __APPLE__
 /*
  * 'appleLangDefault()' - Get the default locale string.
@@ -1374,10 +1386,7 @@ appleMessageLoad(const char *locale)     /* I - Locale ID */
   * plist as the user data.
   */
 
-  return (cupsArrayNew3((cups_array_func_t)cups_message_compare, (void *)plist,
-                        (cups_ahash_func_t)NULL, 0,
-                       (cups_acopy_func_t)NULL,
-                       (cups_afree_func_t)cups_message_free));
+  return (_cupsMessageNew((void *)plist));
 }
 #  endif /* CUPS_BUNDLEDIR */
 #endif /* __APPLE__ */
index fb5841ca5b1235ed8faf8d781c18c94ad1c214ed..b5c5e34cd5e5b066ce8e21e7b1c75c037cf005f2 100644 (file)
@@ -34,7 +34,7 @@
 
 
 /*
- * 'ppdPageSize()' - Get the page size record for the given size.
+ * 'ppdPageSize()' - Get the page size record for the named size.
  */
 
 ppd_size_t *                           /* O - Size record for page or NULL */
index 9e811054ecaad384272bcf73a017389f821463ac..f4850dcf6081bc1da19e916bbe3a9118ab84e4d7 100644 (file)
  *
  * Contents:
  *
- *   _pwgGenerateSize()   - Generate a PWG size keyword.
- *   _pwgInitSize()       - Initialize a PWG size using IPP job template
- *                          attributes.
- *   _pwgMediaForLegacy() - Find a PWG media size by ISO/IPP legacy name.
- *   _pwgMediaForPPD()    - Find a PWG media size by Adobe PPD name.
- *   _pwgMediaForPWG()    - Find a PWG media size by 5101.1 self-describing
- *                          name.
- *   _pwgMediaForSize()   - Get the PWG media name for a given size.
- *   pwg_compare_legacy() - Compare two sizes using the legacy names.
- *   pwg_compare_ppd()    - Compare two sizes using the PPD names.
- *   pwg_compare_pwg()    - Compare two sizes using the PWG names.
  */
 
 /*
@@ -241,6 +230,83 @@ static _pwg_media_t const cups_pwg_media[] =
 };
 
 
+/*
+ * '_pwgFormatInches()' - Convert and format PWG units as inches.
+ */
+
+char *                                 /* O - String */
+_pwgFormatInches(char   *buf,          /* I - Buffer */
+                 size_t bufsize,       /* I - Size of buffer */
+                 int    val)           /* I - Value in hundredths of millimeters */
+{
+  int  thousandths,                    /* Thousandths of inches */
+       integer,                        /* Integer portion */
+       fraction;                       /* Fractional portion */
+
+
+ /*
+  * Convert hundredths of millimeters to thousandths of inches and round to
+  * the nearest thousandth.
+  */
+
+  thousandths = (val * 1000 + 1270) / 2540;
+  integer     = thousandths / 1000;
+  fraction    = thousandths % 1000;
+
+ /*
+  * Format as a pair of integers (avoids locale stuff), avoiding trailing
+  * zeros...
+  */
+
+  if (fraction == 0)
+    snprintf(buf, bufsize, "%d", integer);
+  else if (fraction % 10)
+    snprintf(buf, bufsize, "%d.%03d", integer, fraction);
+  else if (fraction % 100)
+    snprintf(buf, bufsize, "%d.%02d", integer, fraction / 10);
+  else
+    snprintf(buf, bufsize, "%d.%01d", integer, fraction / 100);
+
+  return (buf);
+}
+
+
+/*
+ * '_pwgFormatMillimeters()' - Convert and format PWG units as millimeters.
+ */
+
+char *                                 /* O - String */
+_pwgFormatMillimeters(char   *buf,     /* I - Buffer */
+                      size_t bufsize,  /* I - Size of buffer */
+                      int    val)      /* I - Value in hundredths of millimeters */
+{
+  int  integer,                        /* Integer portion */
+       fraction;                       /* Fractional portion */
+
+
+ /*
+  * Convert hundredths of millimeters to integer and fractional portions.
+  */
+
+  integer     = val / 100;
+  fraction    = val % 100;
+
+ /*
+  * Format as a pair of integers (avoids locale stuff), avoiding trailing
+  * zeros...
+  */
+
+  if (fraction == 0)
+    snprintf(buf, bufsize, "%d", integer);
+  else if (fraction % 10)
+    snprintf(buf, bufsize, "%d.%02d", integer, fraction);
+  else
+    snprintf(buf, bufsize, "%d.%01d", integer, fraction / 10);
+
+  return (buf);
+}
+
+
 /*
  * '_pwgGenerateSize()' - Generate a PWG size keyword.
  */
@@ -253,25 +319,21 @@ _pwgGenerateSize(char       *keyword,     /* I - Keyword buffer */
                 int        width,      /* I - Width of page in 2540ths */
                 int        length)     /* I - Length of page in 2540ths */
 {
-  struct lconv *loc;                   /* Locale conversion data */
-  double       uwidth,                 /* Width in inches or millimeters */
-               ulength;                /* Height in inches or millimeters */
   const char   *units;                 /* Units to report */
   char         usize[12 + 1 + 12 + 3], /* Unit size: NNNNNNNNNNNNxNNNNNNNNNNNNuu */
                *uptr;                  /* Pointer into unit size */
+  char         *(*format)(char *, size_t, int);
+                                       /* Formatting function */
 
 
-  loc = localeconv();
-
   if ((width % 635) == 0 && (length % 635) == 0)
   {
    /*
     * Use inches since the size is a multiple of 1/4 inch.
     */
 
-    uwidth  = width / 2540.0;
-    ulength = length / 2540.0;
     units   = "in";
+    format  = _pwgFormatInches;
 
     if (!prefix)
       prefix = "oe";
@@ -282,26 +344,25 @@ _pwgGenerateSize(char       *keyword,     /* I - Keyword buffer */
     * Use millimeters since the size is not a multiple of 1/4 inch.
     */
 
-    uwidth  = width * 0.01;
-    ulength = length * 0.01;
     units   = "mm";
+    format  = _pwgFormatMillimeters;
 
     if (!prefix)
       prefix = "om";
   }
 
   uptr = usize;
-  _cupsStrFormatd(uptr, uptr + 12, uwidth, loc);
+  (*format)(uptr, sizeof(usize) - (uptr - usize), width);
   uptr += strlen(uptr);
   *uptr++ = 'x';
-  _cupsStrFormatd(uptr, uptr + 12, ulength, loc);
+  (*format)(uptr, sizeof(usize) - (uptr - usize), length);
   uptr += strlen(uptr);
 
  /*
   * Safe because usize can hold up to 12 + 1 + 12 + 4 bytes.
   */
 
-  strcpy(uptr, units);
+  memcpy(uptr, units, 3);
 
   if (!name)
     name = usize;
index 13eedf62d77169595a97d0fccb903d3d05aacc29..33361c1c04f59a53fe28d5ba4019b0c445a3eef4 100644 (file)
@@ -79,6 +79,9 @@ typedef struct _pwg_size_s            /**** Size element - PPD to/from PWG */
  * Functions...
  */
 
+extern char            *_pwgFormatInches(char *buf, size_t bufsize, int val);
+extern char            *_pwgFormatMillimeters(char *buf, size_t bufsize,
+                                              int val);
 extern void            _pwgGenerateSize(char *keyword, size_t keysize,
                                         const char *prefix,
                                         const char *name,
@@ -90,7 +93,6 @@ extern _pwg_media_t   *_pwgMediaForPPD(const char *ppd);
 extern _pwg_media_t    *_pwgMediaForPWG(const char *pwg);
 extern _pwg_media_t    *_pwgMediaForSize(int width, int length);
 
-
 #  ifdef __cplusplus
 }
 #  endif /* __cplusplus */
index 34591e374d3e235ca34b3b667112cc0aff84c048..a10852fa82d0a408e3e873ff027b54a6cc7acd59 100644 (file)
@@ -415,9 +415,8 @@ cupsGetResponse(http_t     *http,   /* I - Connection to server or @code CUPS_HTTP
       ippDelete(response);
       response = NULL;
 
-      _cupsSetError(IPP_SERVICE_UNAVAILABLE, NULL, 0);
       http->status = status = HTTP_ERROR;
-      http->error  = EIO;
+      http->error  = EINVAL;
     }
   }
   else if (status != HTTP_ERROR)
@@ -476,10 +475,6 @@ cupsGetResponse(http_t     *http,  /* I - Connection to server or @code CUPS_HTTP
                   attr ? attr->values[0].string.text :
                      ippErrorString(response->request.status.status_code), 0);
   }
-  else if (status == HTTP_ERROR)
-    _cupsSetError(IPP_INTERNAL_ERROR, strerror(http->error), 0);
-  else if (status != HTTP_OK)
-    _cupsSetHTTPError(status);
 
   return (response);
 }
index d25a78e55c63929552daa53abaeff5b51f350e5b..18bb39cc4af0521f67949162709046fa27d98f7e 100644 (file)
@@ -58,18 +58,107 @@ main(int  argc,                            /* I - Number of command-line arguments */
   int          num_jobs;               /* Number of jobs for queue */
   cups_job_t   *jobs;                  /* Jobs for queue */
 
+
   if (argc > 1)
   {
     if (!strcmp(argv[1], "enum"))
     {
-      int      msec;                   /* Timeout in milliseconds */
-
-      if (argc >= 3)
-        msec = atoi(argv[2]) * 1000;
-      else
-        msec = 0;
-
-      cupsEnumDests(CUPS_DEST_FLAGS_NONE, msec, NULL, 0, 0, enum_cb, NULL);
+      cups_ptype_t     mask = CUPS_PRINTER_LOCAL,
+                                       /* Printer type mask */
+                       type = CUPS_PRINTER_LOCAL;
+                                       /* Printer type */
+      int              msec = 0;       /* Timeout in milliseconds */
+
+
+      for (i = 2; i < argc; i ++)
+        if (isdigit(argv[i][0] & 255) || argv[i][0] == '.')
+          msec = (int)(atof(argv[i]) * 1000);
+        else if (!_cups_strcasecmp(argv[i], "bw"))
+        {
+          mask |= CUPS_PRINTER_BW;
+          type |= CUPS_PRINTER_BW;
+        }
+        else if (!_cups_strcasecmp(argv[i], "color"))
+        {
+          mask |= CUPS_PRINTER_COLOR;
+          type |= CUPS_PRINTER_COLOR;
+        }
+        else if (!_cups_strcasecmp(argv[i], "mono"))
+        {
+          mask |= CUPS_PRINTER_COLOR;
+        }
+        else if (!_cups_strcasecmp(argv[i], "duplex"))
+        {
+          mask |= CUPS_PRINTER_DUPLEX;
+          type |= CUPS_PRINTER_DUPLEX;
+        }
+        else if (!_cups_strcasecmp(argv[i], "simplex"))
+        {
+          mask |= CUPS_PRINTER_DUPLEX;
+        }
+        else if (!_cups_strcasecmp(argv[i], "staple"))
+        {
+          mask |= CUPS_PRINTER_STAPLE;
+          type |= CUPS_PRINTER_STAPLE;
+        }
+        else if (!_cups_strcasecmp(argv[i], "copies"))
+        {
+          mask |= CUPS_PRINTER_COPIES;
+          type |= CUPS_PRINTER_COPIES;
+        }
+        else if (!_cups_strcasecmp(argv[i], "collate"))
+        {
+          mask |= CUPS_PRINTER_COLLATE;
+          type |= CUPS_PRINTER_COLLATE;
+        }
+        else if (!_cups_strcasecmp(argv[i], "punch"))
+        {
+          mask |= CUPS_PRINTER_PUNCH;
+          type |= CUPS_PRINTER_PUNCH;
+        }
+        else if (!_cups_strcasecmp(argv[i], "cover"))
+        {
+          mask |= CUPS_PRINTER_COVER;
+          type |= CUPS_PRINTER_COVER;
+        }
+        else if (!_cups_strcasecmp(argv[i], "bind"))
+        {
+          mask |= CUPS_PRINTER_BIND;
+          type |= CUPS_PRINTER_BIND;
+        }
+        else if (!_cups_strcasecmp(argv[i], "sort"))
+        {
+          mask |= CUPS_PRINTER_SORT;
+          type |= CUPS_PRINTER_SORT;
+        }
+        else if (!_cups_strcasecmp(argv[i], "mfp"))
+        {
+          mask |= CUPS_PRINTER_MFP;
+          type |= CUPS_PRINTER_MFP;
+        }
+        else if (!_cups_strcasecmp(argv[i], "printer"))
+        {
+          mask |= CUPS_PRINTER_MFP;
+        }
+        else if (!_cups_strcasecmp(argv[i], "large"))
+        {
+          mask |= CUPS_PRINTER_LARGE;
+          type |= CUPS_PRINTER_LARGE;
+        }
+        else if (!_cups_strcasecmp(argv[i], "medium"))
+        {
+          mask |= CUPS_PRINTER_MEDIUM;
+          type |= CUPS_PRINTER_MEDIUM;
+        }
+        else if (!_cups_strcasecmp(argv[i], "small"))
+        {
+          mask |= CUPS_PRINTER_SMALL;
+          type |= CUPS_PRINTER_SMALL;
+        }
+        else
+          fprintf(stderr, "Unknown argument \"%s\" ignored...\n", argv[i]);
+
+      cupsEnumDests(CUPS_DEST_FLAGS_NONE, msec, NULL, type, mask, enum_cb, NULL);
     }
     else if (!strcmp(argv[1], "password"))
     {
@@ -416,10 +505,19 @@ enum_cb(void        *user_data,           /* I - User data (unused) */
         unsigned    flags,             /* I - Destination flags */
         cups_dest_t *dest)             /* I - Destination */
 {
+  int          i;                      /* Looping var */
+  cups_option_t        *option;                /* Current option */
+
+
   if (flags & CUPS_DEST_FLAGS_REMOVED)
-    printf("Removed '%s'.\n", dest->name);
+    printf("Removed '%s':\n", dest->name);
   else
-    printf("Added '%s'.\n", dest->name);
+    printf("Added '%s':\n", dest->name);
+
+  for (i = dest->num_options, option = dest->options; i > 0; i --, option ++)
+    printf("    %s=\"%s\"\n", option->name, option->value);
+
+  putchar('\n');
 
   return (1);
 }
index 4c5b4c43db4878c21a5f6ec8e7c9b5818c9c8745..d029588c47aa99ac6841c3787229c2ce0349cdf8 100644 (file)
@@ -248,7 +248,8 @@ cupsCreateJob(
   if (title)
     ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name", NULL,
                  title);
-  cupsEncodeOptions(request, num_options, options);
+  cupsEncodeOptions2(request, num_options, options, IPP_TAG_JOB);
+  cupsEncodeOptions2(request, num_options, options, IPP_TAG_SUBSCRIPTION);
 
  /*
   * Send the request and get the job-id...
index 8555764f9b9f70baee84fac2b72f5467bf0e01bd..1cd0e50365dfe066b50d616f4958785d375bda40 100644 (file)
@@ -494,6 +494,7 @@ information ">cups_dinfo_t</a></li>
        <li><a href="#cups_job_s" title="Job">cups_job_s</a></li>
        <li><a href="#cups_option_s" title="Printer Options">cups_option_s</a></li>
        <li><a href="#cups_size_s" title="Media Size ">cups_size_s</a></li>
+       <li><a href="#pollfd" title="User data (unused)">pollfd</a></li>
 </ul></li>
 <li><a href="#VARIABLES">Variables</a><ul class="code">
        <li><a href="#CF_RETURNS_RETAINED" title="Get the Apple language identifier associated with a
@@ -2690,6 +2691,23 @@ typedef struct <a href="#cups_size_s">cups_size_s</a> cups_size_t;
 <dd class="description">Top margin in hundredths of
 millimeters</dd>
 </dl>
+<h3 class="struct"><a name="pollfd">pollfd</a></h3>
+<p class="description">User data (unused)</p>
+<p class="code">struct pollfd *pollfds, unsigned int num_pollfds, int timeout, void *context) {<br>
+&nbsp;&nbsp;&nbsp;&nbsp;_cups_dnssd_data_t *data;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;else if(val 0) data - got_data;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;void) timeout;<br>
+&nbsp;&nbsp;&nbsp;&nbsp;int val;<br>
+};</p>
+<h4 class="members">Members</h4>
+<dl>
+<dt>data </dt>
+<dd class="description">Enumeration data</dd>
+<dt>got_data </dt>
+<dt>timeout </dt>
+<dt>val </dt>
+<dd class="description">Return value</dd>
+</dl>
 <h2 class="title"><a name="VARIABLES">Variables</a></h2>
 <h3 class="variable"><a name="CF_RETURNS_RETAINED">CF_RETURNS_RETAINED</a></h3>
 <p class="description">Get the Apple language identifier associated with a
index d0162618232600a04ef8912c509d9c07ece1fe75..33b4077a8299387eb70d9931dd720a77faae6a0a 100644 (file)
@@ -434,7 +434,7 @@ conflicts.">ppdMarkOption</a></li>
        <li><a href="#ppdOpenFd" title="Read a PPD file into memory.">ppdOpenFd</a></li>
        <li><a href="#ppdOpenFile" title="Read a PPD file into memory.">ppdOpenFile</a></li>
        <li><a href="#ppdPageLength" title="Get the page length for the given size.">ppdPageLength</a></li>
-       <li><a href="#ppdPageSize" title="Get the page size record for the given size.">ppdPageSize</a></li>
+       <li><a href="#ppdPageSize" title="Get the page size record for the named size.">ppdPageSize</a></li>
        <li><a href="#ppdPageSizeLimits" title="Return the custom page size limits.">ppdPageSizeLimits</a></li>
        <li><a href="#ppdPageWidth" title="Get the page width for the given size.">ppdPageWidth</a></li>
        <li><a href="#ppdSetConformance" title="Set the conformance level for PPD files.">ppdSetConformance</a></li>
@@ -1486,7 +1486,7 @@ float ppdPageLength (<br>
 <h4 class="returnvalue">Return Value</h4>
 <p class="description">Length of page in points or 0.0</p>
 <h3 class="function"><a name="ppdPageSize">ppdPageSize</a></h3>
-<p class="description">Get the page size record for the given size.</p>
+<p class="description">Get the page size record for the named size.</p>
 <p class="code">
 <a href="#ppd_size_t">ppd_size_t</a> *ppdPageSize (<br>
 &nbsp;&nbsp;&nbsp;&nbsp;<a href="#ppd_file_t">ppd_file_t</a> *ppd,<br>
index 24b21335396a0e73a67c3bea2dacfeddea23f5c7..645fd4a1f6a8113e142604cefb1a88bb3b66acd7 100644 (file)
@@ -323,6 +323,11 @@ defined.
 </dt>
 <dd>Requires the EXPECT attribute to use the specified value tag(s).
 </dd>
+<dt>REPEAT-LIMIT number
+</dt>
+<dd></dd>
+<dd>Specifies the maximum number of times to repeat. The default value is 1000.
+</dd>
 <dt>REPEAT-MATCH
 </dt>
 <dd></dd>
@@ -405,6 +410,11 @@ The following predicates are understood following the STATUS test directive:
 </dt>
 <dd>Makes the STATUS apply only if the specified variable is not defined.
 </dd>
+<dt>REPEAT-LIMIT number
+</dt>
+<dd></dd>
+<dd>Specifies the maximum number of times to repeat. The default value is 1000.
+</dd>
 <dt>REPEAT-MATCH
 </dt>
 <dd></dd>
index ef697d5d157f8f6b621a1223c26ac432972f8ec4..8454cf78d53a8b302762e5eea0bc6cf9d719f52b 100644 (file)
@@ -2585,6 +2585,23 @@ on for secure connections. Multiple <CODE>SSLPort</CODE> lines
 can be specified to listen on multiple ports.</P>
 
 
+<H2 CLASS="title"><SPAN CLASS="info">CUPS 1.6</SPAN><A NAME="StrictConformance">StrictConformance</A></H2>
+
+<H3>Examples</H3>
+
+<PRE CLASS="command">
+StrictConformance No
+StrictConformance Yes
+</PRE>
+
+<H3>Description</H3>
+
+<P>The <CODE>StrictConformance</CODE> directive specifies whether the scheduler
+requires strict IPP conformance for client requests, for example to not allow
+document attributes in a Create-Job request. The default is
+<code>No</code>.</P>
+
+
 <H2 CLASS="title"><SPAN CLASS="info">CUPS 1.5</SPAN><A NAME="SubscriptionPrivateAccess">SubscriptionPrivateAccess</A></H2>
 
 <H3>Examples</H3>
index e253e3c486e6323418f3210e415d6cbf89852674..2c66e3202e7eb16d8a2cba41d3621bd9b3800dd3 100644 (file)
 
 <P>This developer guide documents the guidelines and processes we use when developing and maintaining CUPS and related software. Our goal is to provide reliable and efficient software and documentation that addresses the needs of our users.</P>
 
+<H2 CLASS="title"><A NAME="OVERVIEW">Overview</A></H2>
+
+<P>CUPS is developed by Apple Inc. and distributed as open source software under a combination of GNU GPL2 and GNU LGPL2 licenses with exceptions to allow linking to OpenSSL (which has a GPL-incompatible license) and for developers on Apple's operating systems to develop CUPS-based software until alternate license terms. Significant contributions to CUPS must be licensed to Apple using the <A HREF="http://www.cups.org/AppleContributorAgreement_2011-03-10.pdf">Apple Contributor Agreement</A>.</P>
+
+<P>Apple releases updates to the CUPS software approximately every three months. Each release has a version number consisting of the major version (currently 1), minor version (currently 6), and patch version (starting at 0) separated by the period, for example "1.6.0". Releases where only the patch version number changes will contain only bug fixes to the previous release, for example "1.6.1" includes bug fixes for the "1.6.0" release. New features require the major or minor version numbers to change, for example "1.6.0" release contains new features compared to the "1.5.3" release. Multiple beta and "candidate" releases generally precede each new feature release, for example "1.5b1", "1.5b2", and "1.5rc1" preceded the "1.5.0" release. Finally, we also post regular Subversion snapshot releases, for example "1.6svn-r10486", which represent a snapshot of the development for the next feature release.</P>
+
+<P>CUPS interfaces, including the C APIs and command-line arguments, environment variables, configuration files, and output format, are stable across patch versions and are generally backwards-compatible with interfaces used in prior major and minor versions. However, program interfaces such as those used by the scheduler to run filter, port monitor, and backend processes for job processing should only be considered stable from the point of view of a filter, port monitor, or backend. Software that simulates the scheduler in order to run those programs outside of CUPS must necessarily be updated when the corresponding interface is changed in a subsequent CUPS release, otherwise undefined behavior can occur.</P>
+
+<P>CUPS C APIs starting with an underscore (_) are considered to be private to CUPS and are not subject to the normal guarantees of stability between CUPS releases and must <em>never</em> be used in non-CUPS source code. Similarly, configuration and state files written by CUPS are considered private if a corresponding man page is not provided with the CUPS release. <em>Never</em> rely on undocumented files or formats when developing software for CUPS. <em>Always</em> use a published C API to access data stored in a file to avoid compatibility problems in the future.</P>
+
+
 <H2 CLASS="title"><A NAME="COMMUNICATION">Communication</A></H2>
 
 <H3><A NAME="CONTACT">How to Contact the Developers</A></H3>
 
-<P>The <A HREF="http://www.cups.org/newsgroups.php">CUPS
-Forums</A> are the primary means of asking questions and
-informally discussing issues and feature requests with the CUPS
-developers. Table 1 shows the available forums and their
-focus:</P>
+<P>The <A HREF="http://lists.cups.org/">CUPS Mailing Lists</A> are the primary means of asking questions and informally discussing issues and feature requests with the CUPS developers and other experienced CUPS users and developers. Table 1 shows the available mailing lists and their focus:</P>
 
 <DIV CLASS="table"><TABLE SUMMARY="CUPS Forums">
-<CAPTION>Table 1: CUPS Forums</CAPTION>
+<CAPTION>Table 1: CUPS Mailing Lists</CAPTION>
 <TR>
-       <TH>Forum</TH>
+       <TH>List</TH>
        <TH>Focus/Purpose</TH>
 </TR>
 <TR>
-       <TD>cups.bugs</TD>
-       <TD>Discussion of bugs and issues in the CUPS
-       software</TD>
-</TR>
-<TR>
-       <TD>cups.commit</TD>
-       <TD>Report of all commits to the Subversion repository
-       (read-only)</TD>
+       <TD>cups</TD>
+       <TD>General discussion and usage questions for the CUPS software</TD>
 </TR>
 <TR>
-       <TD>cups.ddk</TD>
-       <TD>Usage and development questions for the CUPS Driver
-       Development Kit</TD>
+       <TD>cups-bugs</TD>
+       <TD>Discussion of bugs and issues in the CUPS software</TD>
 </TR>
 <TR>
-       <TD>cups.development</TD>
-       <TD>Development questions and discussion of new features
-       in the CUPS software</TD>
+       <TD>cups-commit</TD>
+       <TD>Report of all commits to the Subversion repository (read-only)</TD>
 </TR>
 <TR>
-       <TD>cups.general</TD>
-       <TD>Usage questions for the CUPS software</TD>
+       <TD>cups-dev</TD>
+       <TD>Development questions and discussion of new features in the CUPS software</TD>
 </TR>
 </TABLE></DIV>
 
+
 <H3><A NAME="SUBMIT">How to Submit a Bug Report or Feature Request</A></H3>
 
-<P>The CUPS "<A HREF="http://www.cups.org/str.php">Bugs &amp;
-Features</A>" page provides access to the CUPS <em>software
-trouble report</em> database and is the formal way to submit a
-bug report or feature request to the CUPS developers. Please
-note, however, that we <em>do not</em> provide answers to usage
-questions or resolve problems in third-party software on this
-page - use the CUPS Forums for that instead.</P>
-
-<P>Unlike discussions that occur on the CUPS Forums, formal bug
-reports and feature requests must be acted on by the CUPS
-developers. This does not mean that every bug report is resolved
-or every feature request is implemented, but we do respond and
-keep track of them all for posterity.</P>
-
-<BLOCKQUOTE>Please use the search feature of the Bugs &amp;
-Features page before submitting a new bug report or feature
-request. If you see an existing report that matches your issue,
-please post a message to that report ("I have this issue as
-well", "I would also like to see", etc.) rather than submitting a
-new report. This helps speed the resolution of your issue by
-reducing the CUPS developers' work load.</BLOCKQUOTE>
+<P>The CUPS "<A HREF="http://www.cups.org/str.php">Bugs &amp; Features</A>" page provides access to the CUPS <em>Software Trouble Report</em> (STR) database and is the formal way to submit a bug report or feature request to the CUPS developers. Please note, however, that we <em>do not</em> provide answers to usage questions or resolve problems in third-party software on this page - use the <A HREF="#CONTACT">CUPS Mailing Lists</A> for that instead.</P>
+
+<P>Unlike discussions that occur on the CUPS Mailing Lists, formal bug reports and feature requests must be acted on by the CUPS developers. This does not mean that every bug report is resolved or every feature request is implemented, but we do respond and keep track of them all for posterity.</P>
+
+<BLOCKQUOTE>Please use the search feature of the Bugs &amp; Features page before submitting a new bug report or feature request. If you see an existing report that matches your issue, please post a message to that report ("I have this issue as well", "I would also like to see", etc.) rather than submitting a new report. This helps speed the resolution of your issue by reducing the CUPS developers' work load and identifying popular issues.</BLOCKQUOTE>
+
 
 <H3><A NAME="PATCH">How to Prepare a Patch</A></H3>
 
-<P>When submitting a bug report or feature request, you can
-include patch files that resolve the bug or implement the feature
-to speed the inclusion of that bug fix or feature in a new CUPS
-release. For changes to existing files, we prefer a unified diff
-against the current Subversion <VAR>trunk</VAR> branch, which can
-be generated easily using the following Subversion command:</P>
+<P>When submitting a bug report or feature request, you can include patch files that resolve the bug or implement the feature to speed the inclusion of that bug fix or feature in a new CUPS release. For changes to existing files, we prefer a unified diff against the current Subversion <VAR>trunk</VAR> branch, which can be generated easily using the following Subversion command:</P>
 
 <PRE CLASS="command">
 svn diff >filename.patch
 </PRE>
 
-<P>If you produce a patch using a released source archive, use
-one of the following commands instead:</P>
+<P>If you produce a patch using a released source archive, use one of the following commands instead:</P>
 
 <PRE CLASS="command">
 diff -u oldfilename filename >filename.patch
@@ -99,36 +78,22 @@ diff -u oldfilename filename >filename.patch
 diff -urN olddirectory directory >filename.patch
 </PRE>
 
-<P>New files and files with significant changes can be submitted
-in their entirety, however that may delay the adoption of your
-changes.</P>
+<P>New files and files with significant changes can be submitted in their entirety, however that may delay the adoption of your changes.</P>
+
+<BLOCKQUOTE><B>Note:</B>
 
-<BLOCKQUOTE>Patches and files must conform to the standards outlined in the
-"<A HREF="#CODING">Coding Guidelines</A>" and "<A HREF="#MAKEFILES">Makefile
-Guidelines</A>" sections in this document. In addition, since Apple Inc.
-provides CUPS under multiple licenses, we require that you assign the copyright
-for your changes and files to us for inclusion in CUPS.</BLOCKQUOTE>
+<P>Patches and files must conform to the standards outlined in the "<A HREF="#CODING">Coding Guidelines</A>" and "<A HREF="#MAKEFILES">Makefile Guidelines</A>" sections in this document. In addition, since Apple Inc. provides CUPS under multiple licenses, we require that you <A HREF="http://www.cups.org/AppleContributorAgreement_2011-03-10.pdf">license</A>  significant changes and files to us for inclusion in CUPS. The CUPS developers will inform you if licensing is required.</P></BLOCKQUOTE>
 
 
 <H2 CLASS="title"><A NAME="PRACTICES">Software Development Practices</A></H2>
 
 <H3><A NAME="VERSIONS">Version Numbering</A></H3>
 
-<P>CUPS uses a three-part version number separated by periods to
-represent the major, minor, and patch release numbers. Major
-release numbers indicate large design changes or
-backwards-incompatible changes to the CUPS API or CUPS Imaging
-API. Minor release numbers indicate new features and other
-smaller changes which are backwards-compatible with previous CUPS
-releases. Patch numbers indicate bug fixes to the previous
-release.</P>
-
-<BLOCKQUOTE>When we talk about compatibility, we are talking
-about binary compatibility for public APIs and output format
-compatibility for program interfaces. Changes to configuration
-file formats or the default behavior of programs are not
-generally considered incompatible as the upgrade process can
-normally address such changes gracefully.</BLOCKQUOTE>
+<P>CUPS uses a three-part version number separated by periods to represent the major, minor, and patch release numbers. Major release numbers indicate large design changes or backwards-incompatible changes to the CUPS API or CUPS Imaging API. Minor release numbers indicate new features and other smaller changes which are backwards-compatible with previous CUPS releases. Patch numbers indicate bug fixes to the previous feature release.</P>
+
+<BLOCKQUOTE><B>Note:</B>
+
+<P>When we talk about compatibility, we are talking about binary compatibility for public APIs and output format compatibility for program interfaces. Changes to configuration file formats or the default behavior of programs are not generally considered incompatible as the upgrade process can normally address such changes gracefully.</P></BLOCKQUOTE>
 
 <P>Production releases use the plain version numbers:</P>
 
@@ -149,59 +114,44 @@ MAJOR.MINOR.PATCH
 2.0.0
 </PRE>
 
-<P>The first production release in a MAJOR.MINOR series (MAJOR.MINOR.0) is
-called a feature release. Feature releases are the only releases that may
-contain new features. Subsequent production releases in a MAJOR.MINOR series may
-only contain bug fixes.</P>
+<P>The first production release in a MAJOR.MINOR series (MAJOR.MINOR.0) is called a feature release. Feature releases are the only releases that may contain new features. Subsequent production releases in a MAJOR.MINOR series may only contain bug fixes.</P>
+
+<BLOCKQUOTE><B>Note:</B>
 
-<BLOCKQUOTE>We did not hold to this limitation in the CUPS 1.1 series for a
-variety of reasons. Starting with CUPS 1.2, the "no new features in a patch
-release" policy has been strictly enforced. The policy has also resulted in
-fewer new features (and interactions!) to validate/test in the subsequence
-feature releases.</BLOCKQUOTE>
+<P>We did not hold to this limitation in the CUPS 1.1 series for a variety of reasons. Starting with CUPS 1.2, the "no new features in a patch release" policy has been strictly enforced. The policy has also resulted in fewer new features (and interactions!) to validate/test in the subsequence feature releases.</P></BLOCKQUOTE>
 
-<P>Beta-test releases are identified by appending the letter B to the major and
-minor version numbers followed by the beta release number:</P>
+<P>Beta-test releases are identified by appending the letter B to the major and minor version numbers followed by the beta release number:</P>
 
 <PRE CLASS="command">
 MAJOR.MINORbNUMBER
 1.2b1
 </PRE>
 
-<P>Release candidates are identified by appending the letters RC to the major
-and minor version numbers followed by the release candidate number:</P>
+<P>Release candidates are identified by appending the letters RC to the major and minor version numbers followed by the release candidate number:</P>
 
 <PRE CLASS="command">
 MAJOR.MINORrcNUMBER
 1.2rc1
 </PRE>
 
-<P>Developer snapshots are identified by appending the letters SVN-R to the
-major and minor version numbers followed by the revision number:</P>
+<P>Developer snapshots are identified by appending the letters SVN-R to the major and minor version numbers followed by the revision number:</P>
 
 <PRE CLASS="command">
 MAJOR.MINORsvn-rREV
 1.2svn-r1234
 </PRE>
 
-<P>Beta-test releases, release candidates, and developer snapshots are only
-created for new minor releases. Once a production release has been made
-(MAJOR.MINOR.0), subsequent patch releases are issues without preliminary beta
-or release testing.</P>
+<P>Beta-test releases, release candidates, and developer snapshots are only created for new minor releases. Once a production release has been made (MAJOR.MINOR.0), subsequent patch releases are issued without preliminary beta or release testing.</P>
 
 <H3>Version Control (Subversion)</H3>
 
-<P>The CUPS source files are managed by the Subversion ("SVN")
-software, available at:</P>
+<P>The CUPS source files are managed by the Subversion ("SVN") software, available at:</P>
 
 <PRE CLASS="command">
-<A HREF="http://subversion.tigris.org/" TARGET="_blank">subversion.tigris.org</A>
+<A HREF="http://subversion.apache.org/" TARGET="_blank">subversion.apache.org</A>
 </PRE>
 
-<P>Source files are "checked in" with each change so that
-modifications can be tracked, and each checkin must reference any
-applicable STRs. The following format <em>must</em> be used for
-commit log messages:</P>
+<P>Source files are "checked in" with each change so that modifications can be tracked, and each checkin must reference any applicable STRs. The following format <em>must</em> be used for commit log messages:</P>
 
 <PRE CLASS="command">
 Summary of the change on one line followed by bug number (STR #NNNN)
@@ -209,10 +159,7 @@ Summary of the change on one line followed by bug number (STR #NNNN)
 Detailed list of changes.
 </PRE>
 
-<P>Primary development occurs on the <var>trunk</var> branch,
-with changes merged back to release branches as needed. Table 2
-shows the URLs developers use for the various CUPS sub-projects
-and branches:</P>
+<P>Primary development occurs on the <var>trunk</var> branch, with changes merged back to release branches as needed. Table 2 shows the URLs developers use for the various CUPS sub-projects and branches:</P>
 
 <DIV CLASS="table"><TABLE SUMMARY="CUPS Subversion URLs">
 <CAPTION>Table 2: CUPS Subversion URLs</CAPTION>
@@ -221,113 +168,55 @@ and branches:</P>
        <TH>Purpose</TH>
 </TR>
 <TR>
-       <TD><A HREF="http://svn.easysw.com/public/cups/trunk/">https://svn.easysw.com/public/cups/trunk/</A></TD>
+       <TD><A HREF="http://svn.cups.org/public/cups/trunk/">https://svn.cups.org/public/cups/trunk/</A></TD>
        <TD>Primary CUPS development branch</TD>
 </TR>
 <TR>
-       <TD><A HREF="http://svn.easysw.com/public/cups/branches/">https://svn.easysw.com/public/cups/branches/</A></TD>
+       <TD><A HREF="http://svn.cups.org/public/cups/branches/">https://svn.cups.org/public/cups/branches/</A></TD>
        <TD>CUPS maintenance branches (merge-only)</TD>
 </TR>
 <TR>
-       <TD><A HREF="http://svn.easysw.com/public/cups/tags/">https://svn.easysw.com/public/cups/tags/</A></TD>
+       <TD><A HREF="http://svn.cups.org/public/cups/tags/">https://svn.cups.org/public/cups/tags/</A></TD>
        <TD>CUPS release tags (read-only)</TD>
 </TR>
-<TR>
-       <TD><A HREF="http://svn.easysw.com/public/windows/trunk/">https://svn.easysw.com/public/windows/trunk/</A></TD>
-       <TD>Primary CUPS Windows Driver development branch</TD>
-</TR>
-<TR>
-       <TD><A HREF="http://svn.easysw.com/public/windows/branches/">https://svn.easysw.com/public/windows/branches/</A></TD>
-       <TD>CUPS Windows Driver maintenance branches (merge-only)</TD>
-</TR>
-<TR>
-       <TD><A HREF="http://svn.easysw.com/public/windows/tags/">https://svn.easysw.com/public/windows/tags/</A></TD>
-       <TD>CUPS Windows Driver release tags (read-only)</TD>
-</TR>
 </TABLE></DIV>
 
-<P>The branch for a MAJOR.MINOR release are created when the
-first production release (MAJOR.MINOR.0) is made using the name
-"branch-MAJOR.MINOR". Release tags are created for every beta,
-candidate, and production release using the name
-"release-MAJOR.MINOR.PATCHbNUMBER",
-"release-MAJOR.MINOR.PATCHrcNUMBER", or
-"release-MAJOR.MINOR.PATCH", respectively. No release tags are
-created for developer snapshots.</P>
+<P>The branch for a MAJOR.MINOR release are created when the first production release (MAJOR.MINOR.0) is made using the name "branch-MAJOR.MINOR". Release tags are created for every beta, candidate, and production release using the name "release-MAJOR.MINORbNUMBER", "release-MAJOR.MINORrcNUMBER", or "release-MAJOR.MINOR.PATCH", respectively. No release tags are created for developer snapshots.</P>
 
 
 <H3>Files and Directories</H3>
 
-<P>File and directory names may not exceed 16 characters in
-length to ensure compatibility with older UNIX filesystems. In
-addition, to avoid problems with case-insensitive filesystems,
-you may not use names which differ only by case, for example
-"ReadMe" and "README" are not allowed in the same directory.</P>
+<P>File and directory names may not exceed 16 characters in length to ensure compatibility with older UNIX filesystems. In addition, to avoid problems with case-insensitive filesystems, you may not use names which differ only by case, for example "ReadMe" and "README" are not allowed in the same directory.</P>
 
-<P>Source files must be documented and formatted as described in
-"<A HREF="#CODING">Coding Requirements</A>". Make files must
-follow the guidelines in "<A HREF="#MAKEFILE">Makefile
-Guidelines</A>".</P>
+<P>Source files must be documented and formatted as described in "<A HREF="#CODING">Coding Requirements</A>". Makefiles must follow the guidelines in "<A HREF="#MAKEFILE">Makefile Guidelines</A>".</P>
 
 
 <H3>Build System</H3>
 
-<P>The CUPS build system uses <A
-HREF="http://www.gnu.org/software/autoconf/">GNU autoconf</A> to
-tailor the library to the local operating system. Project files
-for major IDEs are also provided for Microsoft
-Windows<SUP>&reg;</SUP>. To improve portability, makefiles must
-not make use of the unique features offered by <A
-HREF="http://www.gnu.org/software/make/">GNU make</A>. See the <A
-HREF="#MAKEFILES">Makefile Guidelines</A> section for a
-description of the allowed make features and makefile
-guidelines.</P>
-
-<P>Additional GNU build programs such as <A
-HREF="http://www.gnu.org/software/automake">GNU automake</A> and
-<A HREF="http://www.gnu.org/software/libtool">GNU libtool</A>
-must not be used. GNU automake produces non-portable makefiles
-which depend on GNU-specific extensions, and GNU libtool is not
-portable or reliable enough for CUPS.</P>
+<P>The CUPS build system uses <A HREF="http://www.gnu.org/software/autoconf/">GNU autoconf</A> to tailor the library to the local operating system. Project files for the current release of Visual C++ are also provided for Microsoft Windows<SUP>&reg;</SUP>. To improve portability, makefiles must not make use of features unique to <A HREF="http://www.gnu.org/software/make/">GNU make</A>. See the <A HREF="#MAKEFILES">Makefile Guidelines</A> section for a description of the allowed make features and makefile guidelines.</P>
+
+<P>Additional GNU build programs such as <A HREF="http://www.gnu.org/software/automake">GNU automake</A> and <A HREF="http://www.gnu.org/software/libtool">GNU libtool</A> must not be used. GNU automake produces non-portable makefiles which depend on GNU-specific extensions, and GNU libtool is not portable or reliable enough for CUPS.</P>
 
 
 <H3><A NAME="PACKAGING">Packaging</A></H3>
 
-<P>Source packages are created using the
-<VAR>tools/makesrcdist</VAR> script in the Subversion repository.
-The script optionally uses a version number argument:</P>
+<P>Source packages are created using the <VAR>tools/makesrcdist</VAR> script in the Subversion repository. The script optionally uses a version number argument:</P>
 
 <PRE CLASS="command">
 tools/makesrcdist
 tools/makesrcdist <I>version</I>
 </PRE>
 
-<P>When run with no arguments, the script creates a snapshot of
-the current working copy and names it using the highest revision
-number in the WC, for example
-"/tmp/cups-1.3svn-r1234-source.tar.bz2" and
-"/tmp/cups-1.3svn-r1234-source.tar.gz". When run with two
-arguments, the script creates a release tag in the repository and
-exports that tag, creating the files
-"/tmp/cups-<I>version</I>-source.tar.bz2" and
-"/tmp/cups-<I>version</I>-source.tar.gz".</P>
-
-<P>Binary packages are not generally distributed by the CUPS
-team, however the <VAR>packaging/cups.spec</VAR> and
-<VAR>packaging/cups.list</VAR> files may be used to create binary
-packages on Linux, OS X, and UNIX. The
-<VAR>packaging/cups.spec</VAR> file produces a binary package
-using the <CODE>rpmbuild(8)</CODE> software:</P>
+<P>When run with no arguments, the script creates a snapshot of the current working copy and names it using the highest revision number in the WC, for example "/tmp/cups-1.3svn-r1234-source.tar.bz2" and "/tmp/cups-1.3svn-r1234-source.tar.gz". When run with two arguments, the script creates a release tag in the repository and exports that tag, creating the files
+"/tmp/cups-<I>version</I>-source.tar.bz2" and "/tmp/cups-<I>version</I>-source.tar.gz".</P>
+
+<P>Binary packages are not generally distributed by the CUPS team, however the <VAR>packaging/cups.spec</VAR> and <VAR>packaging/cups.list</VAR> files may be used to create binary packages on Linux, OS X, and UNIX. The <VAR>packaging/cups.spec</VAR> file produces a binary package using the <CODE>rpmbuild(8)</CODE> software:</P>
 
 <PRE CLASS="command">
 rpmbuild -ta cups-<I>version</I>-source.tar.gz
 </PRE>
 
-<P>The <VAR>cups.list</VAR> file is generated by the
-<VAR>configure</VAR> script and produces binary packages for many
-platforms using the <A HREF="http://www.easysw.com/epm/"
-TARGET="_blank">EPM</A> software. Table 3 shows the targets that
-are available for each type of binary package:</P>
+<P>The <VAR>cups.list</VAR> file is generated by the <VAR>configure</VAR> script and produces binary packages for many platforms using the <A HREF="http://www.epmhome.org/" TARGET="_blank">EPM</A> software. Table 3 shows the targets that are available for each type of binary package:</P>
 
 <DIV CLASS="table"><TABLE SUMMARY="Binary Package Targets">
 <CAPTION>Table 3: Binary Package Targets</CAPTION>
@@ -359,10 +248,6 @@ are available for each type of binary package:</P>
        <TD>inst</TD>
        <TD>IRIX inst/tardist</TD>
 </TR>
-<TR>
-       <TD>osx</TD>
-       <TD>OS X Install</TD>
-</TR>
 <TR>
        <TD>pkg</TD>
        <TD>Solaris pkgadd</TD>
@@ -389,10 +274,7 @@ are available for each type of binary package:</P>
 </TR>
 </TABLE></DIV>
 
-<P>Finally, the <VAR>tools/testrpm</VAR> and
-<VAR>tools/testosx</VAR> scripts can be used to create binary
-packages from the current working copy for testing on Linux and
-OS X, respectively:</P>
+<P>Finally, the <VAR>tools/testrpm</VAR> and <VAR>tools/testosx</VAR> scripts can be used to create binary packages from the current working copy for testing on Linux and OS X, respectively:</P>
 
 <PRE CLASS="command">
 tools/testrpm
@@ -405,26 +287,18 @@ open cups.pkg
 
 <H3><A NAME="TESTING">Testing</A></H3>
 
-<P>Software testing is conducted according to the <A
-HREF="spec-stp.html">CUPS Software Test Plan</A>. This testing is
-automated via the top-level makefile <VAR>test</VAR> target:</P>
+<P>Software testing is conducted according to the <A HREF="spec-stp.html">CUPS Software Test Plan</A>. This testing is automated via the top-level makefile <VAR>test</VAR> target:</P>
 
 <PRE CLASS="command">
 make test
 </PRE>
 
-<P>The test environment allows for both short-term automated
-testing and long-term testing and development without the
-automated test script.</P>
+<P>The test environment allows for both short-term automated testing and long-term testing and development without the automated test script.</P>
 
 
 <H2 CLASS="title"><A NAME="STR">Trouble Report Processing</A></H2>
 
-<P>A Software Trouble Report ("STR") must be submitted every time
-a user or vendor experiences a problem with the CUPS software.
-Trouble reports are maintained on the <A
-HREF="http://www.cups.org/str.php" TARGET="_blank">Bugs &amp;
-Features</A> page with one of the following states:</P>
+<P>A Software Trouble Report ("STR") must be submitted every time a user or vendor experiences a problem with the CUPS software. Trouble reports are maintained on the <A HREF="http://www.cups.org/str.php" TARGET="_blank">Bugs &amp; Features</A> page with one of the following states:</P>
 
 <OL>
 
@@ -442,36 +316,25 @@ Features</A> page with one of the following states:</P>
 
 <P>Trouble reports are processed using the following steps.</P>
 
-<OL>
+<H3>1. Classification</H3>
 
-<LI>Classification
-
-<P>When a trouble report is received it must be classified at one
-of the following priority levels:</P>
+<P>When a trouble report is received it must be classified at one of the following priority levels:</P>
 
 <OL>
 
-       <LI>Request for enhancement, e.g. asking for a
-       feature
+       <LI>Request for enhancement, e.g. asking for a feature
 
-       <LI>Low, e.g. a documentation error or undocumented
-       side-effect
+       <LI>Low, e.g. a documentation error or undocumented side-effect
 
-       <LI>Moderate, e.g. unable to print a file or unable to
-       compile the software
+       <LI>Moderate, e.g. unable to print a file or unable to compile the software
 
-       <LI>High, e.g. unable to print to a printer or key
-       functionality not working
+       <LI>High, e.g. unable to print to a printer or key functionality not working
 
        <LI>Critical, e.g. unable to print at all
 
 </OL>
 
-<P>Level 4 and 5 trouble reports must be resolved in the next
-software release. Level 2 and 3 trouble reports are scheduled for
-resolution in a specific release at the discretion of the release
-coordinator. Level 1 trouble reports are scheduled for resolution
-in a future feature release.</P>
+<P>Level 4 and 5 trouble reports must be resolved in the next software release. Level 2 and 3 trouble reports are scheduled for resolution in a specific release at the discretion of the release coordinator. Level 1 trouble reports are scheduled for resolution in a future feature release.</P>
 
 <P>The scope of the problem is also determined as:</P>
 
@@ -485,43 +348,24 @@ in a future feature release.</P>
 
 </OL>
 
-<LI>Identification
-
-<P>Once the level and scope of the trouble report is determined
-the software sub-system(s) involved with the problem are
-determined. This may involve additional communication with the
-user or vendor to isolate the problem to a specific cause.</P>
+<H3>2. Identification</H3>
 
-<P>When the sub-system(s) involved have been identified, an
-engineer will then determine the change(s) needed and estimate
-the time required for the change(s).</P>
+<P>Once the level and scope of the trouble report is determined the software sub-system(s) involved with the problem are determined. This may involve additional communication with the user or vendor to isolate the problem to a specific cause.</P>
 
-<LI>Correction
+<P>When the sub-system(s) involved have been identified, an engineer will then determine the change(s) needed and estimate the time required for the change(s).</P>
 
-<P>Corrections are scheduled based upon the severity and
-complexity of the problem. Once all changes have been made,
-documented, and tested successfully a new software release
-snapshot is generated. Additional tests are added as necessary
-for proper testing of the changes.</P>
+<H3>3. Correction</H3>
 
-<LI>Notification
+<P>Corrections are scheduled based upon the severity and complexity of the problem. Once all changes have been made, documented, and tested successfully a new software release snapshot is generated. Additional tests are added as necessary for proper testing of the changes.</P>
 
-<P>The user or vendor is notified when the fix is available or if
-the problem was caused by user error.</P>
+<H3>4. Notification</H3>
 
-</OL>
+<P>The user or vendor is notified when the fix is available or if the problem was caused by user error.</P>
 
 
 <H2 CLASS="title"><A NAME="RELEASES">Release Management</A></H2>
 
-<P>When testing has been completed successfully, a new source
-package is created using the <VAR>tools/makesrcdist</VAR> script.
-Three types of releases, beta, candidate, and production, are
-created and released to the public using the basic schedule in
-Table 4. At least one beta and one release candidate must be
-created prior to a production release, and there must be at least
-two weeks between the last beta and first candidate and last
-candidate and first production release.</P>
+<P>When testing has been completed successfully, a new source package is created using the <VAR>tools/makesrcdist</VAR> script. Three types of releases - beta, candidate, and production - are created and released to the public using the basic schedule in Table 4. At least one beta and one release candidate must be created prior to a production release, and there must be at least two weeks between the last beta and first candidate and last candidate and first production release.</P>
 
 <DIV CLASS="table"><TABLE SUMMARY="CUPS Basic Release Schedule">
 <CAPTION>Table: CUPS Basic Release Schedule</CAPTION>
@@ -560,25 +404,18 @@ candidate and first production release.</P>
 
 <H2 CLASS="title"><A NAME="CODING">Coding Guidelines</A></H2>
 
-<P>These coding guidelines provide detailed information on source
-file formatting and documentation content and must be applied to
-all C and C++ source files provided with CUPS. Source code for
-other languages should conform to these guidelines as allowed by
-the language.</P>
+<P>These coding guidelines provide detailed information on source file formatting and documentation content and must be applied to all C and C++ source files provided with CUPS. Source code for other languages should conform to these guidelines as allowed by the language.</P>
+
 
 <H3>Source Files</H3>
 
-<P>All source files names shall be 16 characters or less in
-length to ensure compatibility with older UNIX filesystems.
-Source files containing functions shall have an extension of ".c"
-for ANSI C and ".cxx" for C++ source files. All other "include"
-files shall have an extension of ".h".</P>
+<P>All source files names must be 16 characters or less in length to ensure compatibility with older UNIX filesystems. Source files containing functions have an extension of ".c" for ANSI C and ".cxx" for C++ source files. All other "include" files have an extension of ".h". Tabs are set to 8 characters.</P>
 
-<P>The top of each source file shall contain a header giving the
-name of the file, the purpose or nature of the source file, the
-copyright and licensing notice, and the functions contained in
-the file.  The file name and revision information is provided by
-the Subversion "&#36;Id$" tag:</P>
+<BLOCKQUOTE><B>Note:</B>
+
+<P>The ".cxx" extension is used because it is the only common C++ extension between Linux, OS X, UNIX, and Windows.</P></BLOCKQUOTE>
+
+<P>The top of each source file contains a header giving the name of the file, the purpose or nature of the source file, the copyright and licensing notice, and the functions contained in the file.  The file name and revision information is provided by the Subversion "&#36;Id$" tag:</P>
 
 <PRE CLASS="command">
 /*
@@ -586,7 +423,7 @@ the Subversion "&#36;Id$" tag:</P>
  *
  *   Description of file contents.
  *
- *   Copyright 2010 by Apple Inc.
+ *   Copyright 2012 by Apple Inc.
  *
  *   These coded instructions, statements, and computer programs are the
  *   property of Apple Inc. and are protected by Federal copyright
@@ -602,19 +439,13 @@ the Subversion "&#36;Id$" tag:</P>
  */
 </PRE>
 
-<P>For source files that are subject to the Apple OS-Developed
-Software exception, the following additional comment should
-appear after the contact information:</P>
+<P>For source files that are subject to the Apple OS-Developed Software exception, the following additional comment appears after the contact information:</P>
 
 <PRE CLASS="command">
  *   This file is subject to the Apple OS-Developed Software exception.
 </PRE>
 
-<P>The bottom of each source file shall contain a trailer giving
-the name of the file using the Subversion "&#36;Id$" tag. The
-primary purpose of this is to mark the end of a source file; if
-the trailer is missing it is possible that code has been lost
-near the end of the file:</P>
+<P>The bottom of each source file contains a trailer giving the name of the file using the Subversion "&#36;Id$" tag. The primary purpose of this is to mark the end of a source file; if the trailer is missing it is possible that code has been lost near the end of the file:</P>
 
 <PRE CLASS="command">
 /*
@@ -622,22 +453,92 @@ near the end of the file:</P>
  */
 </PRE>
 
+
+<H3>Comments</H3>
+
+<P>All source code utilizes block comments within functions to describe the operations being performed by a group of statements; avoid putting a comment per line unless absolutely necessary, and then consider refactoring the code so that it is not necessary.  C source files use the block comment format ("/* comment */") since many vendor C compilers still do not support C99/C++ comments ("// comment"):</P>
+
+<PRE CLASS="command">
+ /*
+  * Clear the state array before we begin...
+  */
+
+  for (i = 0; i &lt; (sizeof(array) / sizeof(sizeof(array[0])); i ++)
+    array[i] = CUPS_STATE_IDLE;
+
+ /*
+  * Wait for state changes on another thread...
+  */
+
+  do
+  {
+    for (i = 0; i &lt; (sizeof(array) / sizeof(sizeof(array[0])); i ++)
+      if (array[i] != CUPS_STATE_IDLE)
+        break;
+
+    if (i == (sizeof(array) / sizeof(array[0])))
+      sleep(1);
+  } while (i == (sizeof(array) / sizeof(array[0])));
+</PRE>
+
+<H3>Indentation</H3>
+
+<P>All code blocks enclosed by brackets begin with the opening brace on a new line. The code then follows starting on a new line after the brace and is indented 2 spaces. The closing brace is then placed on a new line following the code at the original indentation:</P>
+
+<PRE CLASS="command">
+{
+  int i; /* Looping var */
+
+
+ /*
+  * Process foobar values from 0 to 999...
+  */
+
+  for (i = 0; i &lt; 1000; i ++)
+  {
+    do_this(i);
+    do_that(i);
+  }
+}
+</PRE>
+
+<P>Single-line statements following "do", "else", "for", "if", and "while" are indented 2 spaces as well. Blocks of code in a "switch" block are indented 4 spaces after each "case" and "default" case:</P>
+
+<PRE CLASS="command">
+switch (array[i])
+{
+  case CUPS_STATE_IDLE :
+      do_this(i);
+      do_that(i);
+      break;
+  default :
+      do_nothing(i);
+      break;
+}
+</PRE>
+
+
+<H3>Spacing</H3>
+
+<P>A space follows each reserved word such as "if", "while", etc. Spaces are not inserted between a function name and the arguments in parenthesis.</P>
+
+
+<H3>Return Values</H3>
+
+<P>Parenthesis surround values returned from a function:</P>
+
+<PRE CLASS="command">
+return (CUPS_STATE_IDLE);
+</PRE>
+
+
 <H3>Functions</H3>
 
-<P>Functions with a global scope shall have a lowercase prefix
-followed by capitalized words ("cupsDoThis", "cupsDoThat",
-"cupsDoSomethingElse", etc.) Private global functions shall begin
-with a leading underscore ("_cupsDoThis", "_cupsDoThat",
-etc.)</P>
+<P>Functions with a global scope have a lowercase prefix followed by capitalized words, e.g., "cupsDoThis", "cupsDoThat", "cupsDoSomethingElse", etc. Private global functions begin with a leading underscore, e.g., "_cupsDoThis", "_cupsDoThat", etc.</P>
 
-<P>Functions with a local scope shall be declared "static" and be
-lowercase with underscores between words ("do_this", "do_that",
-"do_something_else", etc.)</P>
+<P>Functions with a local scope are declared "static" with lowercase names and underscores between words, e.g., "do_this", "do_that", "do_something_else", etc.</P>
 
-<P>Each function shall begin with a comment header describing
-what the function does, the possible input limits (if any), and
-the possible output values (if any), and any special information
-needed:</P>
+<P>Each function begins with a comment header describing what the function does, the possible input limits (if any), and the possible output values (if any), and any special information needed:</P>
 
 <PRE CLASS="command">
 /*
@@ -654,100 +555,68 @@ do_this(float x)                        /* I - Power value (0.0 &lt;= x &lt;= 1.
 }
 </PRE>
 
-<P>Return/output values are indicated using an "O" prefix, input
-values are indicated using the "I" prefix, and values that are
-both input and output use the "IO" prefix for the corresponding
-in-line comment.</P>
+<P>Return/output values are indicated using an "O" prefix, input values are indicated using the "I" prefix, and values that are both input and output use the "IO" prefix for the corresponding in-line comment.</P>
 
-<P>The Mini-XML documentation generator also understands the following
-special text in the function description comment:</P>
+<P>The Mini-XML documentation generator also understands the following special text in the function description comment:</P>
 
 <UL>
 
-       <LI><CODE>@deprecated@</CODE> - Marks the function as
-       deprecated (not recommended for new development and
-       scheduled for removal)</LI>
+       <LI><CODE>@deprecated@</CODE> - Marks the function as deprecated (not recommended for new development and scheduled for removal)</LI>
 
-       <LI><CODE>@since CUPS <I>version</I>@</CODE> - Marks the
-       function as new in the specified version of CUPS.</LI>
+       <LI><CODE>@since CUPS <I>version</I>@</CODE> - Marks the function as new in the specified version of CUPS.</LI>
 
-       <LI><CODE>@private@</CODE> - Marks the function as private.</LI>
+       <LI><CODE>@private@</CODE> - Marks the function as private (same as starting the function name with an underscore)</LI>
 
 </UL>
 
+
 <H3>Variables</H3>
 
-<P>Variables with a global scope shall be capitalized
-("ThisVariable", "ThatVariable", "ThisStateVariable", etc.) The
-only exception to this rule shall be the CUPS interface library
-global variables which must begin with the prefix "cups"
-("cupsThisVariable", "cupsThatVariable", etc.) Global variables
-shall be replaced by function arguments whenever possible.</P>
+<P>Variables with a global scope are capitalized, e.g., "ThisVariable", "ThatVariable", "ThisStateVariable", etc. Globals in CUPS libraries are either part of the per-thread global values managed by the "_cupsGlobals()" function or are suitably protected for concurrent access. Global variables should be replaced by function arguments whenever possible.</P>
 
-<P>Variables with a local scope shall be lowercase with
-underscores between words ("this_variable", "that_variable",
-etc.) Any local variables shared by functions within a source
-file shall be declared "static".</P>
+<P>Variables with a local scope are lowercase with underscores between words, e.g., "this_variable", "that_variable", etc. Any "local global" variables shared by functions within a source file are declared "static". As for global variables, local static variables are suitably protected for concurrent access.</P>
 
-<P>Each variable shall be declared on a separate line and shall
-be immediately followed by a comment block describing the
-variable:</P>
+<P>Each variable is declared on a separate line and is immediately followed by a comment block describing the variable:</P>
 
 <PRE CLASS="command">
-int this_variable;   /* The current state of this */
-int that_variable;   /* The current state of that */
+int         ThisVariable;    /* The current state of this */
+static int  that_variable;   /* The current state of that */
 </PRE>
 
+
 <H3>Types</H3>
 
-<P>All type names shall be lowercase with underscores between
-words and "_t" appended to the end of the name
-("cups_this_type_t", "cups_that_type_t", etc.) Type names must
-start with a prefix, typically "cups" or the name of the program,
-to avoid conflicts with system types. Private type names must
-start with an underscore ("_cups_this_t", "_cups_that_t",
-etc.)</P>
+<P>All type names are lowercase with underscores between words and "_t" appended to the end of the name, e.g., "cups_this_type_t", "cups_that_type_t", etc. Type names start with a prefix, typically "cups" or the name of the program, to avoid conflicts with system types. Private type names start with an underscore, e.g., "_cups_this_t", "_cups_that_t", etc.</P>
 
-<P>Each type shall have a comment block immediately after the
-typedef:</P>
+<P>Each type has a comment block immediately after the typedef:</P>
 
 <PRE CLASS="command">
-typedef int cups_this_type_t;           /* This type is for CUPS foobar options. */
+typedef int cups_this_type_t;       /* This type is for CUPS foobar options. */
 </PRE>
 
+
 <H3>Structures</H3>
 
-<P>All structure names shall be lowercase with underscores
-between words and "_s" appended to the end of the name
-("cups_this_s", "cups_that_s", etc.) Structure names must start
-with a prefix, typically "cups" or the name of the program, to
-avoid conflicts with system types. Private structure names must
-start with an underscore ("_cups_this_s", "_cups_that_s",
-etc.)</P>
+<P>All structure names are lowercase with underscores between words and "_s" appended to the end of the name, e.g., "cups_this_s", "cups_that_s", etc. Structure names start with a prefix, typically "cups" or the name of the program, to avoid conflicts with system types. Private structure names start with an underscore, e.g., "_cups_this_s", "_cups_that_s", etc.</P>
 
-<P>Each structure shall have a comment block immediately after
-the struct and each member shall be documented in accordance with
-the variable naming policy above:</P>
+<P>Each structure has a comment block immediately after the struct and each member is documented similar to the variable naming policy above:</P>
 
 <PRE CLASS="command">
-struct cups_this_struct_s               /* This structure is for CUPS foobar options. */
+struct cups_this_struct_s     /* This structure is for CUPS foobar options. */
 {
-  int this_member;                      /* Current state for this */
-  int that_member;                      /* Current state for that */
+  int this_member;            /* Current state for this */
+  int that_member;            /* Current state for that */
 };
 </PRE>
 
+
 <H3>Constants</H3>
 
-<P>All constant names shall be uppercase with underscored between
-words ("CUPS_THIS_CONSTANT", "CUPS_THAT_CONSTANT", etc.)
-Constants must begin with an uppercase prefix, typically "CUPS"
-or the program name.</P>
+<P>All constant names are uppercase with underscores between words, e.g., "CUPS_THIS_CONSTANT", "CUPS_THAT_CONSTANT", etc. Constants begin with an uppercase prefix, typically "CUPS" or the program name. Private constants start with an underscore, e.g., "_CUPS_THIS_CONSTANT", "_CUPS_THAT_CONSTANT", etc.</P>
 
-<P>Typed enumerations shall be used whenever possible to allow
-for type checking by the compiler.</P>
+<P>Typed enumerations should be used whenever possible to allow for type checking by the compiler.</P>
 
-<P>Comment blocks shall immediately follow each constant:</P>
+<P>Comment blocks immediately follow each constant:</P>
 
 <PRE CLASS="command">
 enum
@@ -757,124 +626,20 @@ enum
 };
 </PRE>
 
-<H3>Code</H3>
-
-<P>All source code shall utilize block comments within functions
-to describe the operations being performed by a group of
-statements; avoid putting a comment per line unless absolutely
-necessary, and then consider refactoring the code so that it is
-not necessary:</P>
-
-<PRE CLASS="command">
-/*
- * Clear the state array before we begin...
- */
-
-for (i = 0; i &lt; (sizeof(array) / sizeof(sizeof(array[0])); i ++)
-  array[i] = STATE_IDLE;
-
-/*
- * Wait for state changes...
- */
-
-do
-{
-  for (i = 0; i &lt; (sizeof(array) / sizeof(sizeof(array[0])); i ++)
-    if (array[i] != STATE_IDLE)
-      break;
-
-  if (i == (sizeof(array) / sizeof(array[0])))
-    sleep(1);
-} while (i == (sizeof(array) / sizeof(array[0])));
-</PRE>
-
-<H3>Indentation</H3>
-
-<P>All code blocks enclosed by brackets shall begin with the
-opening brace on a new line. The code then follows starting on a
-new line after the brace and is indented 2 spaces. The closing
-brace is then placed on a new line following the code at the
-original indentation:</P>
-
-<PRE CLASS="command">
-{
-  int i; /* Looping var */
-
- /*
-  * Process foobar values from 0 to 999...
-  */
-
-  for (i = 0; i &lt; 1000; i ++)
-  {
-    do_this(i);
-    do_that(i);
-  }
-}
-</PRE>
-
-<P>Single-line statements following "do", "else", "for", "if",
-and "while" shall be indented 2 spaces as well. Blocks of code
-in a "switch" block shall be indented 4 spaces after each "case"
-and "default" case:</P>
-
-<PRE CLASS="command">
-switch (array[i])
-{
-  case STATE_IDLE :
-      do_this(i);
-      do_that(i);
-      break;
-  default :
-      do_nothing(i);
-      break;
-}
-</PRE>
-
-<H3>Spacing</H3>
-
-<P>A space shall follow each reserved word ("if", "while", etc.)
-Spaces shall not be inserted between a function name and the
-arguments in parenthesis.</P>
-
-<H3>Return Values</H3>
-
-<P>Parenthesis shall surround values returned from a function
-using "return":</P>
-
-<PRE CLASS="command">
-return (CUPS_STATE_IDLE);
-</PRE>
-
-<H3>Loops</H3>
-
-<P>Whenever convenient loops should count downward to zero to
-improve program performance:</P>
-
-<PRE CLASS="command">
-for (i = sizeof(array) / sizeof(array[0]) - 1; i >= 0; i --)
-  array[i] = CUPS_STATE_IDLE;
-</PRE>
 
 <H2 CLASS="title"><A NAME="MAKEFILES">Makefile Guidelines</A></H2>
 
-<P>The following is a guide to the makefile-based build system
-used by CUPS. These standards have been developed over the years
-to allow CUPS to be built on as many systems and environments as
-possible.</P>
+<P>The following is a guide to the makefile-based build system used by CUPS. These standards have been developed over the years to allow CUPS to be built on as many systems and environments as possible.</P>
+
 
 <H3>General Organization</H3>
 
-<P>The CUPS source code is organized functionally into a
-top-level makefile, include file, and subdirectories each with
-their own makefile and dependencies files. The ".in" files are
-template files for the <CODE>autoconf</CODE> software and are
-used to generate a static version of the corresponding file.</P>
+<P>The CUPS source code is organized functionally into a top-level makefile, include file, and subdirectories each with their own makefile and dependencies files. The ".in" files are template files for the <CODE>autoconf</CODE> software and are used to generate a static version of the corresponding file.</P>
+
 
 <H3>Makefile Documentation</H3>
 
-<P>Each make file must start with the standard CUPS header
-containing the Subversion "&#36;Id$" keyword, description of the
-file, and CUPS copyright and license notice:</P>
+<P>Each makefile starts with the standard CUPS header containing the Subversion "&#36;Id$" keyword, description of the file, and CUPS copyright and license notice:</P>
 
 <PRE CLASS="command">
 #
@@ -882,7 +647,7 @@ file, and CUPS copyright and license notice:</P>
 #
 #   Makefile for ...
 #
-#   Copyright 2007 by Apple Inc.
+#   Copyright 2012 by Apple Inc.
 #
 #   These coded instructions, statements, and computer programs are the
 #   property of Apple Inc. and are protected by Federal copyright
@@ -892,7 +657,7 @@ file, and CUPS copyright and license notice:</P>
 #
 </PRE>
 
-<P>The end of each makefile must have a comment saying:</P>
+<P>The end of each makefile has a comment saying:</P>
 
 <PRE CLASS="command">
 #
@@ -900,28 +665,21 @@ file, and CUPS copyright and license notice:</P>
 #
 </PRE>
 
-<P>The purpose of the trailer is to indicate the end of the
-makefile so that truncations are immediately obvious.</P>
+<P>The purpose of the trailer is to indicate the end of the makefile so that truncations are immediately obvious.</P>
+
 
 <H3>Portable Makefile Construction</H3>
 
-<P>CUPS uses a common subset of make program syntax to ensure
-that the software can be compiled "out of the box" on as many
-systems as possible. The following is a list of assumptions we
-follow when constructing makefiles:</P>
+<P>CUPS uses a common subset of make program syntax to ensure that the software can be compiled "out of the box" on as many systems as possible. The following is a list of assumptions we follow when constructing makefiles:</P>
 
 <UL>
 
-       <LI><b>Targets</b>; we assume that the make program
-       supports the notion of simple targets of the form
-       "name:" that perform tab-indented commands that follow
-       the target, e.g.:
+       <LI><b>Targets</b>; we assume that the make program supports the notion of simple targets of the form "name:" that perform tab-indented commands that follow the target, e.g.:
        <PRE CLASS="command">
 target:
 &rarr; target commands</PRE></LI>
 
-       <LI><b>Dependencies</b>; we assume that the make program
-       supports recursive dependencies on targets, e.g.:
+       <LI><b>Dependencies</b>; we assume that the make program supports recursive dependencies on targets, e.g.:
        <PRE CLASS="command">
 target: foo bar
 &rarr; target commands
@@ -935,28 +693,21 @@ bar:
 bla:
 &rarr; bla commands</PRE></LI>
 
-       <LI><b>Variable Definition</b>; we assume that the make program
-       supports variable definition on the command-line or in the makefile
-       using the following form:
+       <LI><b>Variable Definition</b>; we assume that the make program supports variable definition on the command-line or in the makefile using the following form:
        <PRE CLASS="command">
 name=value</PRE>
 
-       <LI><b>Variable Substitution</b>; we assume that the make program
-       supports variable substitution using the following forms:
+       <LI><b>Variable Substitution</b>; we assume that the make program supports variable substitution using the following forms:
        <UL>
                <LI><CODE>$(name)</CODE>; substitutes the value of "name",</LI>
-               <LI><CODE>($name:.old=.new)</CODE>; substitutes the value of "name"
-               with the filename extensions ".old" changed to ".new",</LI>
-               <LI><CODE>$(MAKEFLAGS)</CODE>; substitutes the
-               command-line options passed to the program
-               without the leading hyphen (-),</LI>
+               <LI><CODE>($name:.old=.new)</CODE>; substitutes the value of "name"     with the filename extension ".old" changed to ".new",</LI>
+               <LI><CODE>$(MAKEFLAGS)</CODE>; substitutes the command-line options passed to the program without the leading hyphen (-),</LI>
                <LI><CODE>$$</CODE>; substitutes a single <CODE>$</CODE> character,</LI>
                <LI><CODE>$&lt;</CODE>; substitutes the current source file or dependency, and</LI>
                <LI><CODE>$@</CODE>; substitutes the current target name.</LI>
        </UL></LI>
 
-       <LI><b>Suffixes</b>; we assume that the make program
-       supports filename suffixes with assumed dependencies, e.g.:
+       <LI><b>Suffixes</b>; we assume that the make program supports filename suffixes with assumed dependencies, e.g.:
        <PRE CLASS="command">
 .SUFFIXES: .c .o
 .c.o:
@@ -968,64 +719,67 @@ name=value</PRE>
 include ../Makedefs
 include Dependencies</PRE></LI>
 
-       <LI><b>Comments</b>; we assume that comments begin with
-       a <CODE>#</CODE> character and proceed to the end of the
-       current line.</LI>
+       <LI><b>Comments</b>; we assume that comments begin with a <CODE>#</CODE> character and proceed to the end of the current line.</LI>
 
-       <LI><b>Line Length</b>; we assume that there is no
-       practical limit to the length of lines.</LI>
+       <LI><b>Line Length</b>; we assume that there is no practical limit to the length of lines.</LI>
 
-       <LI><b>Continuation of long lines</b>; we assume that
-       the <CODE>\</CODE> character may be placed at the end of a
-       line to concatenate two or more lines in a
-       makefile to form a single long line.</LI>
+       <LI><b>Continuation of long lines</b>; we assume that the <CODE>\</CODE> character may be placed at the end of a line to concatenate two or more lines in a makefile to form a single long line.</LI>
 
-       <LI><b>Shell</b>; we assume a POSIX-compatible shell is
-       present on the build system.</LI>
+       <LI><b>Shell</b>; we assume a POSIX-compatible shell is present on the build system.</LI>
 
 </UL>
 
+
 <H3>Standard Variables</H3>
 
-<P>The following variables are defined in the "Makedefs" file
-generated by the <CODE>autoconf</CODE> software:</P>
+<P>The following variables are defined in the "Makedefs" file generated by the <CODE>autoconf</CODE> software:</P>
 
 <UL>
 
-       <LI><CODE>AR</CODE>; the library archiver command,</LI>
+       <LI><CODE>ALL_CFLAGS</CODE>; the combined C compiler options,</LI>
 
-       <LI><CODE>ARFLAGS</CODE>; options for the library archiver command,</LI>
-
-       <LI><CODE>BUILDROOT</CODE>; optional installation prefix,</LI>
+       <LI><CODE>ALL_CXXFLAGS</CODE>; the combined C++ compiler options,</LI>
 
-       <LI><CODE>MAN1EXT</CODE>; extension for man pages in section 1,</LI>
+       <LI><CODE>AMANDIR</CODE>; the administrative man page installation directory (section 8/1m depending on the platform),</LI>
 
-       <LI><CODE>MAN3EXT</CODE>; extension for man pages in section 3,</LI>
+       <LI><CODE>AR</CODE>; the library archiver command,</LI>
 
-       <LI><CODE>MAN5EXT</CODE>; extension for man pages in section 5,</LI>
+       <LI><CODE>ARFLAGS</CODE>; options for the library archiver command,</LI>
 
-       <LI><CODE>MAN7EXT</CODE>; extension for man pages in section 7,</LI>
+       <LI><CODE>AWK</CODE>; the local awk command,</LI>
 
-       <LI><CODE>MAN8DIR</CODE>; subdirectory for man pages in section 8,</LI>
+       <LI><CODE>BINDIR</CODE>; the binary installation directory,</LI>
 
-       <LI><CODE>MAN8EXT</CODE>; extension for man pages in section 8,</LI>
+       <LI><CODE>BUILDROOT</CODE>; optional installation prefix (defaults to DSTROOT),</LI>
 
        <LI><CODE>CC</CODE>; the C compiler command,</LI>
 
        <LI><CODE>CFLAGS</CODE>; options for the C compiler command,</LI>
 
+       <LI><CODE>CHMOD</CODE>; the chmod command,</LI>
+
        <LI><CODE>CXX</CODE>; the C++ compiler command,</LI>
 
        <LI><CODE>CXXFLAGS</CODE>; options for the C++ compiler command,</LI>
 
-       <LI><CODE>DSOCOMMAND</CODE>; the shared library building command,</LI>
+       <LI><CODE>DATADIR</CODE>; the data file installation directory,</LI>
+
+       <LI><CODE>DSO</CODE>; the C shared library building command,</LI>
+
+       <LI><CODE>DSOXX</CODE>; the C++ shared library building command,</LI>
 
        <LI><CODE>DSOFLAGS</CODE>; options for the shared library building command,</LI>
 
+       <LI><CODE>INCLUDEDIR</CODE>; the public header file installation directory,</LI>
+
        <LI><CODE>INSTALL</CODE>; the <CODE>install</CODE> command,</LI>
 
        <LI><CODE>INSTALL_BIN</CODE>; the program installation command,</LI>
 
+       <LI><CODE>INSTALL_COMPDATA</CODE>; the compressed data file installation command,</LI>
+
+       <LI><CODE>INSTALL_CONFIG</CODE>; the configuration file installation command,</LI>
+
        <LI><CODE>INSTALL_DATA</CODE>; the data file installation command,</LI>
 
        <LI><CODE>INSTALL_DIR</CODE>; the directory installation command,</LI>
@@ -1036,77 +790,82 @@ generated by the <CODE>autoconf</CODE> software:</P>
 
        <LI><CODE>INSTALL_SCRIPT</CODE>; the shell script installation command,</LI>
 
+       <LI><CODE>LD</CODE>; the linker command,</LI>
+
        <LI><CODE>LDFLAGS</CODE>; options for the linker,</LI>
 
+       <LI><CODE>LIBDIR</CODE>; the library installation directory,</LI>
+
        <LI><CODE>LIBS</CODE>; libraries for all programs,</LI>
 
        <LI><CODE>LN</CODE>; the <CODE>ln</CODE> command,</LI>
 
-       <LI><CODE>OPTIM</CODE>; common compiler optimization options,</LI>
+       <LI><CODE>MAN1EXT</CODE>; extension for man pages in section 1,</LI>
 
-       <LI><CODE>RM</CODE>; the <CODE>rm</CODE> command,</LI>
+       <LI><CODE>MAN3EXT</CODE>; extension for man pages in section 3,</LI>
 
-       <LI><CODE>SHELL</CODE>; the <CODE>sh</CODE> (POSIX shell) command,</LI>
+       <LI><CODE>MAN5EXT</CODE>; extension for man pages in section 5,</LI>
 
-       <LI><CODE>STRIP</CODE>; the <CODE>strip</CODE> command,</LI>
+       <LI><CODE>MAN7EXT</CODE>; extension for man pages in section 7,</LI>
 
-       <LI><CODE>bindir</CODE>; the binary installation directory,</LI>
+       <LI><CODE>MAN8DIR</CODE>; subdirectory for man pages in section 8,</LI>
+
+       <LI><CODE>MAN8EXT</CODE>; extension for man pages in section 8,</LI>
 
-       <LI><CODE>datadir</CODE>; the data file installation directory,</LI>
+       <LI><CODE>MANDIR</CODE>; the man page installation directory,</LI>
 
-       <LI><CODE>exec_prefix</CODE>; the installation prefix for executable files,</LI>
+       <LI><CODE>OPTIM</CODE>; common compiler optimization options,</LI>
+
+       <LI><CODE>PRIVATEINCLUDE</CODE>; the private header file installation directory,</LI>
 
-       <LI><CODE>libdir</CODE>; the library installation directory,</LI>
+       <LI><CODE>RM</CODE>; the <CODE>rm</CODE> command,</LI>
 
-       <LI><CODE>mandir</CODE>; the man page installation directory,</LI>
+       <LI><CODE>SHELL</CODE>; the <CODE>sh</CODE> (POSIX shell) command,</LI>
 
-       <LI><CODE>prefix</CODE>; the installation prefix for non-executable files, and</LI>
+       <LI><CODE>STRIP</CODE>; the <CODE>strip</CODE> command,</LI>
 
        <LI><CODE>srcdir</CODE>; the source directory.</LI>
 
 </UL>
 
+
 <H3>Standard Targets</H3>
 
-<P>The following standard targets must be defined in each
-makefile:</P>
+<P>The following standard targets are defined in each makefile:</P>
 
 <UL>
 
-       <LI><CODE>all</CODE>; creates all target programs,
-       libraries, and documentation files,</LI>
+       <LI><CODE>all</CODE>; creates all target programs, libraries, and documentation files,</LI>
+
+       <LI><CODE>clean</CODE>; removes all target programs libraries, documentation files, and object files,</LI>
+
+       <LI><CODE>depend</CODE>; generates automatic dependencies for any C or C++ source files (also see <A HREF="#DEPEND_TARGET">"Dependencies"</A>),</LI>
+
+       <LI><CODE>distclean</CODE>; removes autoconf-generated files in addition to those removed by the "clean" target,</LI>
+
+       <LI><CODE>install</CODE>; installs all distribution files in their corresponding locations (also see <A HREF="#INSTALL_TARGET">"Install/Uninstall Support"</A>),</LI>
 
-       <LI><CODE>clean</CODE>; removes all target programs,
-       libraries, documentation files, and object files,</LI>
+       <LI><CODE>install-data</CODE>; installs all data files in their corresponding locations (also see <A HREF="#INSTALL_TARGET">"Install/Uninstall Support"</A>),</LI>
 
-       <LI><CODE>depend</CODE>; generates automatic dependencies
-       for any C or C++ source files (also see <A
-       HREF="#DEPEND_TARGET">"Dependencies"</A>),</LI>
+       <LI><CODE>install-exec</CODE>; installs all executable files in their corresponding locations (also see <A HREF="#INSTALL_TARGET">"Install/Uninstall Support"</A>),</LI>
 
-       <LI><CODE>distclean</CODE>; removes autoconf-generated files
-       in addition to those removed by the "clean" target,</LI>
+       <LI><CODE>install-headers</CODE>; installs all include files in their corresponding locations (also see <A HREF="#INSTALL_TARGET">"Install/Uninstall Support"</A>),</LI>
 
-       <LI><CODE>install</CODE>; installs all distribution files in
-       their corresponding locations (also see <A
-       HREF="#INSTALL_TARGET">"Install/Uninstall Support"</A>), </LI>
+       <LI><CODE>install-libs</CODE>; installs all library files in their corresponding locations (also see <A HREF="#INSTALL_TARGET">"Install/Uninstall Support"</A>),</LI>
 
-       <LI><CODE>uninstall</CODE>; removes all distribution files from
-       their corresponding locations (also see <A
-       HREF="#INSTALL_TARGET">"Install/Uninstall Support"</A>), and</LI>
+       <LI><CODE>uninstall</CODE>; removes all distribution files from their corresponding locations (also see <A HREF="#INSTALL_TARGET">"Install/Uninstall Support"</A>), and</LI>
 
 </UL>
 
 
 <H3>Object Files</H3>
 
-<P>Object files (the result of compiling a C or C++ source file)
-have the extension ".o".</P>
+<P>Object files (the result of compiling a C or C++ source file) have the extension ".o".</P>
+
 
 <H3>Programs</H3>
 
-<P>Program files are the result of linking object files and
-libraries together to form an executable file. A typical
-program target looks like:</P>
+<P>Program files are the result of linking object files and libraries together to form an executable file. A typical program target looks like:</P>
 
 <PRE CLASS="command">
 program: $(OBJS)
@@ -1114,10 +873,10 @@ program: $(OBJS)
 &rarr; $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
 </PRE>
 
+
 <H3>Static Libraries</H3>
 
-<P>Static libraries have a prefix of "lib" and the extension
-".a". A typical static library target looks like:</P>
+<P>Static libraries have a prefix of "lib" and the extension ".a". A typical static library target looks like:</P>
 
 <PRE CLASS="command">
 libname.a: $(OBJECTS)
@@ -1127,12 +886,10 @@ libname.a: $(OBJECTS)
 &rarr; $(RANLIB) $@
 </PRE>
 
+
 <H3>Shared Libraries</H3>
 
-<P>Shared libraries have a prefix of "lib" and the extension
-".dylib", ".sl", ".so", or "_s.a" depending on the operating
-system. A typical shared library is composed of several targets
-that look like:</P>
+<P>Shared libraries have a prefix of "lib" and the extension ".dylib", ".sl", ".so", or "_s.a" depending on the operating system. A typical shared library is composed of several targets that look like:</P>
 
 <PRE CLASS="command">
 libname.so: $(OBJECTS)
@@ -1173,46 +930,29 @@ libname_s.a: $(OBJECTS)
 
 <H3>Dependencies</H3>
 
-<P>Static dependencies are expressed in each makefile following the
-target, for example:</P>
+<P>Static dependencies are expressed in each makefile following the target, for example:</P>
 
 <PRE CLASS="command">
 foo: bar
 </PRE>
 
-<P>Static dependencies shall only be used when it is not
-possible to automatically generate them. Automatic dependencies
-are stored in a file named "Dependencies" and included at the
-end of the makefile. The following "depend" target rule shall be
-used to create the automatic dependencies:
+<P>Static dependencies are only used when it is not possible to automatically generate them. Automatic dependencies are stored in a file named "Dependencies" and included at the end of the makefile. The following "depend" target rule is used to create the automatic dependencies:
 
 <PRE CLASS="command">
 depend:
-&rarr; $(MAKEDEPEND) -Y -I.. -f Dependencies $(OBJS:.o=.c)
+&rarr; $(CC) -MM $(ALL_CFLAGS) $(OBJS:.o=.c) >Dependencies
 </PRE>
 
-<P>We only regenerate the automatic dependencies on a Linux
-system and express any non-Linux dependencies statically in the
-makefile.</P>
+<P>We regenerate the automatic dependencies on an OS X system and express any non-OS X dependencies statically in the makefile.</P>
+
 
 <H3><A NAME="TARGET_INSTALL">Install/Uninstall Support</A></H3>
 
-<P>All makefiles must contain install and uninstall rules which
-install or remove the corresponding software. These rules must
-use the <CODE>$(BUILDROOT)</CODE> variable as a prefix to any
-installation directory so that CUPS can be installed in a
-temporary location for packaging by programs like
-<CODE>rpmbuild</CODE>.</P>
-
-<P>The <CODE>$(INSTALL_BIN)</CODE>, <CODE>$(INSTALL_DATA)</CODE>,
-<CODE>$(INSTALL_DIR)</CODE>, <CODE>$(INSTALL_LIB)</CODE>,
-<CODE>$(INSTALL_MAN)</CODE>, and <CODE>$(INSTALL_SCRIPT)</CODE>
-variables must be used when installing files so that the proper
-ownership and permissions are set on the installed files.</P>
-
-<P>The <CODE>$(RANLIB)</CODE> command must be run on any static
-libraries after installation since the symbol table is
-invalidated when the library is copied on some platforms.</P>
+<P>All makefiles contains install and uninstall rules which install or remove the corresponding software. These rules must use the <CODE>$(BUILDROOT)</CODE> variable as a prefix to any installation directory so that CUPS can be installed in a temporary location for packaging by programs like <CODE>rpmbuild</CODE>.</P>
+
+<P>The <CODE>$(INSTALL_BIN)</CODE>, <CODE>$(INSTALL_COMPDATA)</CODE>, <CODE>$(INSTALL_CONFIG)</CODE>, <CODE>$(INSTALL_DATA)</CODE>, <CODE>$(INSTALL_DIR)</CODE>, <CODE>$(INSTALL_LIB)</CODE>, <CODE>$(INSTALL_MAN)</CODE>, and <CODE>$(INSTALL_SCRIPT)</CODE> variables must be used when installing files so that the proper ownership and permissions are set on the installed files.</P>
+
+<P>The <CODE>$(RANLIB)</CODE> command must be run on any static libraries after installation since the symbol table is invalidated when the library is copied on some platforms.</P>
 
 </BODY>
 </HTML>
index d85918978986c2d48ebf0e9977a445c4e1caf829..ec0a03091370562568f82b19d08f615b36dee758 100644 (file)
@@ -397,6 +397,7 @@ div.contents ul.subcontents li {
        <li><a href="#cupsMediaQualifier3">cupsMediaQualifier3</a></li>
        <li><a href="#cupsMinSize">cupsMinSize</a></li>
        <li><a href="#cupsMaxSize">cupsMaxSize</a></li>
+       <li><a href="#cupsPageSizeCategory">cupsPageSizeCategory</a></li>
 </ul></li>
 <li><a href="#ATTRIBUTES">General Attributes</a><ul class="subcontents">
        <li><a href="#cupsBackSide">cupsBackSide</a></li>
@@ -1398,6 +1399,21 @@ are used to identify options to use for matching.</p>
 </pre>
 
 
+<h3><span class='info'>CUPS 1.4/OS X 10.6</span><a name='cupsPageSizeCategory'>cupsPageSizeCategory</a></h3>
+
+<p class="summary">*cupsPageSizeCategory name/text: "name name2 ... nameN"</p>
+
+<p>This keyword lists related paper size names that should be grouped together in the Print or Page Setup dialogs. The "name" portion of the keyword specifies the root/default size for the grouping. On OS X the grouped paper sizes are shown in a submenu of the main paper size. When omitted, sizes with the same dimensions are automatically grouped together, for example "Letter" and "Letter.Borderless".</p>
+
+<p>Example:</p>
+
+<pre class="command">
+<em>*% Specify grouping of borderless/non-borderless sizes</em>
+*cupsPageSizeCategory Letter/US Letter: "Letter Letter.Borderless"
+*cupsPageSizeCategory A4/A4: "A4 A4.Borderless"
+</pre>
+
+
 <h2 class='title'><a name='ATTRIBUTES'>General Attributes</a></h2>
 
 <h3><span class='info'>CUPS 1.3/OS X 10.5</span><a name='cupsBackSide'>cupsBackSide</a></h3>
@@ -1776,6 +1792,7 @@ the output for a specific model of printer.</p>
 *cupsModelNumber: 1234
 </pre>
 
+
 <h3><span class='info'>CUPS 1.3/OS X 10.5</span><a name='cupsPJLCharset'>cupsPJLCharset</a></h3>
 
 <p class='summary'>*cupsPJLCharset: "ISO character set name"</p>
@@ -2236,6 +2253,8 @@ the device.</p>
 
 <ul>
 
+    <li>Added <a href="#cupsPageSizeCategory"><tt>cupsPageSizeCategory</tt></a> keyword (originally defined in CUPS 1.4).</li>
+
        <li>Added <a href="#cupsMaxCopies"><tt>cupsMaxCopies</tt></a> keyword.</li>
 
        <li>Documented <a href="#JCLToPDFInterpreter"><tt>JCLToPDFInterpreter</tt></a> keyword.</li>
diff --git a/examples/ppdx.c b/examples/ppdx.c
new file mode 100644 (file)
index 0000000..61588ca
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * "$Id$"
+ *
+ *   Example code for encoding and decoding large amounts of data in a PPD file.
+ *   This would typically be used in a driver to save configuration/state
+ *   information that could be used by an application.
+ *
+ *   Copyright 2012 by Apple Inc.
+ *
+ *   These coded instructions, statements, and computer programs are the
+ *   property of Apple Inc. and are protected by Federal copyright
+ *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ *   which should have been included with this file.  If this file is
+ *   file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ *   This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ *   ppdxReadData()  - Read encoded data from a ppd_file_t *.
+ *   ppdxWriteData() - Writes encoded data to stderr using PPD: messages.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "ppdx.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <zlib.h>                      /* For compression of the data */
+
+
+/*
+ * Constants...
+ */
+
+#define PPDX_MAX_VALUE (PPD_MAX_LINE - PPD_MAX_NAME - 4)
+                                       /* Max value length with delimiters + nul */
+#define PPDX_MAX_CHUNK (PPDX_MAX_VALUE * 3 / 4)
+                                       /* Max length of each chunk when Base64-encoded */
+
+
+/*
+ * 'ppdxReadData()' - Read encoded data from a ppd_file_t *.
+ *
+ * Reads chunked data in the PPD file "ppd" using the prefix "name".  Returns
+ * an allocated pointer to the data (which is nul-terminated for convenience)
+ * along with the length of the data in the variable pointed to by "datasize",
+ * which can be NULL to indicate the caller doesn't need the length.
+ *
+ * Returns NULL if no data is present in the PPD with the prefix.
+ */
+
+void *                                 /* O - Data or NULL */
+ppdxReadData(ppd_file_t *ppd,          /* I - PPD file */
+             const char *name,         /* I - Keyword prefix */
+             size_t     *datasize)     /* O - Size of data or NULL for don't care */
+{
+  char         keyword[PPD_MAX_NAME],  /* Keyword name */
+               decoded[PPDX_MAX_CHUNK + 1];
+                                       /* Decoded string */
+  unsigned     chunk = 0;              /* Current chunk number */
+  int          len;                    /* Length of current chunk */
+  ppd_attr_t   *attr;                  /* Keyword/value from PPD file */
+  Bytef                *data;                  /* Pointer to data */
+  size_t       alloc_size;             /* Allocated size of data buffer */
+  z_stream     decomp;                 /* Decompressor stream */
+  int          error;                  /* Error/status from inflate() */
+
+
+ /*
+  * Range check input...
+  */
+
+  if (datasize)
+    *datasize = 0;
+
+  if (!ppd || !name)
+    return (NULL);
+
+ /*
+  * First see if there are any instances of the named keyword in the PPD...
+  */
+
+  snprintf(keyword, sizeof(keyword), "%s%04x", name, chunk);
+  if ((attr = ppdFindAttr(ppd, keyword, NULL)) == NULL)
+    return (NULL);
+
+ /*
+  * Allocate some memory and start decoding...
+  */
+
+  data       = malloc(257);
+  alloc_size = 256;
+
+  memset(&decomp, 0, sizeof(decomp));
+  decomp.next_out  = data;
+  decomp.avail_out = 256;
+
+  inflateInit(&decomp);
+
+  do
+  {
+   /*
+    * Grab the data from the current attribute and decode it...
+    */
+
+    len = sizeof(decoded);
+    if (!httpDecode64_2(decoded, &len, attr->value) || len == 0)
+      break;
+
+//    printf("chunk %04x has length %d\n", chunk, len);
+
+   /*
+    * Decompress this chunk...
+    */
+
+    decomp.next_in  = decoded;
+    decomp.avail_in = len;
+
+    do
+    {
+      Bytef    *temp;                  /* Temporary pointer */
+      size_t   temp_size;              /* Temporary allocation size */
+
+//      printf("Before inflate: avail_in=%d, avail_out=%d\n", decomp.avail_in,
+//             decomp.avail_out);
+
+      if ((error = inflate(&decomp, Z_NO_FLUSH)) < Z_OK)
+      {
+        fprintf(stderr, "ERROR: inflate returned %d (%s)\n", error, decomp.msg);
+        break;
+      }
+
+//      printf("After inflate: avail_in=%d, avail_out=%d, error=%d\n",
+//             decomp.avail_in, decomp.avail_out, error);
+
+      if (decomp.avail_out == 0)
+      {
+       if (alloc_size < 2048)
+         temp_size = alloc_size * 2;
+       else if (alloc_size < PPDX_MAX_DATA)
+         temp_size = alloc_size + 2048;
+       else
+         break;
+
+       if ((temp = realloc(data, temp_size + 1)) == NULL)
+       {
+         free(data);
+         return (NULL);
+       }
+
+       decomp.next_out  = temp + (decomp.next_out - data);
+       decomp.avail_out = temp_size - alloc_size;
+       data             = temp;
+       alloc_size       = temp_size;
+      }
+    }
+    while (decomp.avail_in > 0);
+
+    chunk ++;
+    snprintf(keyword, sizeof(keyword), "%s%04x", name, chunk);
+  }
+  while ((attr = ppdFindAttr(ppd, keyword, NULL)) != NULL);
+
+  inflateEnd(&decomp);
+
+ /*
+  * Nul-terminate the data (usually a string)...
+  */
+
+  *(decomp.next_out) = '\0';
+
+  if (datasize)
+    *datasize = decomp.next_out - data;
+
+  return (data);
+}
+
+
+/*
+ * 'ppdxWriteData()' - Writes encoded data to stderr using PPD: messages.
+ *
+ * Writes chunked data to the PPD file using PPD: messages sent to stderr for
+ * cupsd.  "name" must be a valid PPD keyword string whose length is less than
+ * 37 characters to allow for chunk numbering.  "data" provides a pointer to the
+ * data to be written, and "datasize" provides the length.
+ */
+
+extern void
+ppdxWriteData(const char *name,                /* I - Base name of keyword */
+              const void *data,                /* I - Data to write */
+              size_t     datasize)     /* I - Number of bytes in data */
+{
+  char         buffer[PPDX_MAX_CHUNK], /* Chunk buffer */
+               encoded[PPDX_MAX_VALUE + 1],
+                                       /* Encoded data */
+               pair[PPD_MAX_LINE],     /* name=value pair */
+               line[PPDX_MAX_STATUS],  /* Line buffer */
+               *lineptr,               /* Current position in line buffer */
+               *lineend;               /* End of line buffer */
+  unsigned     chunk = 0;              /* Current chunk number */
+  int          len;                    /* Length of current chunk */
+  z_stream     comp;                   /* Compressor stream */
+  int          error;                  /* Error/status from deflate() */
+
+
+ /*
+  * Range check input...
+  */
+
+  if (!name || (!data && datasize > 0) || datasize > PPDX_MAX_DATA)
+    return;
+
+  strlcpy(line, "PPD:", sizeof(line));
+  lineptr = line + 4;
+  lineend = line + sizeof(line) - 2;
+
+  if (datasize > 0)
+  {
+   /*
+    * Compress and encode output...
+    */
+
+    memset(&comp, 0, sizeof(comp));
+    comp.next_in   = (Bytef *)data;
+    comp.avail_in  = datasize;
+
+    deflateInit(&comp, 9);
+
+    do
+    {
+     /*
+      * Compress a chunk...
+      */
+
+      comp.next_out  = buffer;
+      comp.avail_out = sizeof(buffer);
+
+      if ((error = deflate(&comp, Z_FINISH)) < Z_OK)
+      {
+        fprintf(stderr, "ERROR: deflate returned %d (%s)\n", error, comp.msg);
+        break;
+      }
+
+     /*
+      * Write a chunk...
+      */
+
+      len = sizeof(buffer) - comp.avail_out;
+      httpEncode64_2(encoded, sizeof(encoded), buffer, len);
+
+      len = (int)snprintf(pair, sizeof(pair), " %s%04x=%s", name, chunk,
+                         encoded);
+#ifdef DEBUG
+      fprintf(stderr, "DEBUG: *%s%04x: \"%s\"\n", name, chunk, encoded);
+#endif /* DEBUG */
+
+      if ((lineptr + len) >= lineend)
+      {
+       *lineptr++ = '\n';
+       *lineptr   = '\0';
+
+       fputs(line, stderr);
+       lineptr = line + 4;
+      }
+
+      strlcpy(lineptr, pair, lineend - lineptr);
+      lineptr += len;
+
+     /*
+      * Setup for the next one...
+      */
+
+      chunk ++;
+    }
+    while (comp.avail_out == 0);
+  }
+
+  deflateEnd(&comp);
+
+ /*
+  * Write a trailing empty chunk to signal EOD...
+  */
+
+  len = (int)snprintf(pair, sizeof(pair), " %s%04x=\"\"", name, chunk);
+#ifdef DEBUG
+  fprintf(stderr, "DEBUG: *%s%04x: \"\"\n", name, chunk);
+#endif /* DEBUG */
+
+  if ((lineptr + len) >= lineend)
+  {
+    *lineptr++ = '\n';
+    *lineptr   = '\0';
+
+    fputs(line, stderr);
+    lineptr = line + 4;
+  }
+
+  strlcpy(lineptr, pair, lineend - lineptr);
+  lineptr += len;
+
+  *lineptr++ = '\n';
+  *lineptr   = '\0';
+
+  fputs(line, stderr);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/examples/ppdx.h b/examples/ppdx.h
new file mode 100644 (file)
index 0000000..1be6928
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * "$Id$"
+ *
+ *   Header for PPD data encoding example code.
+ *
+ *   Copyright 2012 by Apple Inc.
+ *
+ *   These coded instructions, statements, and computer programs are the
+ *   property of Apple Inc. and are protected by Federal copyright
+ *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ *   which should have been included with this file.  If this file is
+ *   file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ *   This file is subject to the Apple OS-Developed Software exception.
+ *
+ */
+
+#ifndef _PPDX_H_
+#  define _PPDX_H_
+
+
+/*
+ * Include necessary headers...
+ */
+
+#  include <cups/ppd.h>
+
+
+/*
+ * C++ magic...
+ */
+
+#  ifdef __cplusplus
+extern "C" {
+#  endif /* __cplusplus */
+
+
+/*
+ * Maximum amount of data to encode/decode...
+ */
+
+#  define PPDX_MAX_STATUS      1024    /* Limit on log messages in 10.6 */
+#  define PPDX_MAX_DATA                16777216/* 16MiB */
+
+
+/*
+ * 'ppdxReadData()' - Read encoded data from a ppd_file_t *.
+ *
+ * Reads chunked data in the PPD file "ppd" using the prefix "name".  Returns
+ * an allocated pointer to the data (which is nul-terminated for convenience)
+ * along with the length of the data in the variable pointed to by "datasize",
+ * which can be NULL to indicate the caller doesn't need the length.
+ *
+ * Returns NULL if no data is present in the PPD with the prefix.
+ */
+
+extern void    *ppdxReadData(ppd_file_t *ppd, const char *name,
+                             size_t *datasize);
+
+
+/*
+ * 'ppdxWriteData()' - Writes encoded data to stderr using PPD: messages.
+ *
+ * Writes chunked data to the PPD file using PPD: messages sent to stderr for
+ * cupsd.  "name" must be a valid PPD keyword string whose length is less than
+ * 37 characters to allow for chunk numbering.  "data" provides a pointer to the
+ * data to be written, and "datasize" provides the length.
+ */
+
+extern void    ppdxWriteData(const char *name, const void *data,
+                             size_t datasize);
+
+
+#  ifdef __cplusplus
+}
+#  endif /* __cplusplus */
+
+#endif /* !_PPDX_H */
+
+/*
+ * End of "$Id$".
+ */
diff --git a/examples/testppdx.c b/examples/testppdx.c
new file mode 100644 (file)
index 0000000..f1c1686
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * "$Id$"
+ *
+ *   Test program for PPD data encoding example code.
+ *
+ *   Compile with:
+ *
+ *       gcc -o testppdx -D_PPD_DEPRECATED="" -g testppdx.c ppdx.c -lcups -lz
+ *
+ *   Copyright 2012 by Apple Inc.
+ *
+ *   These coded instructions, statements, and computer programs are the
+ *   property of Apple Inc. and are protected by Federal copyright
+ *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ *   which should have been included with this file.  If this file is
+ *   file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ *   This file is subject to the Apple OS-Developed Software exception.
+ *
+ * Contents:
+ *
+ *   main() - Read data from a test PPD file and write out new chunks.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "ppdx.h"
+
+
+/*
+ * 'main()' - Read data from a test PPD file and write out new chunks.
+ */
+
+int                                    /* O - Exit status */
+main(void)
+{
+  int          status = 0;             /* Exit status */
+  FILE         *fp;                    /* File to read */
+  char         contents[8193],         /* Contents of file */
+               *data;                  /* Data from PPD */
+  size_t       contsize,               /* File size */
+               datasize;               /* Data size */
+  ppd_file_t   *ppd;                   /* Test PPD */
+
+
+ /*
+  * Open the PPD and get the data from it...
+  */
+
+  ppd  = ppdOpenFile("testppdx.ppd");
+  data = ppdxReadData(ppd, "EXData", &datasize);
+
+ /*
+  * Open this source file and read it...
+  */
+
+  fp = fopen("testppdx.c", "r");
+  if (fp)
+  {
+    contsize = fread(contents, 1, sizeof(contents) - 1, fp);
+    fclose(fp);
+    contents[contsize] = '\0';
+  }
+  else
+  {
+    contents[0] = '\0';
+    contsize    = 0;
+  }
+
+ /*
+  * Compare data...
+  */
+
+  if (data)
+  {
+    if (contsize != datasize)
+    {
+      fprintf(stderr, "ERROR: PPD has %ld bytes, test file is %ld bytes.\n",
+              (long)datasize, (long)contsize);
+      status = 1;
+    }
+    else if (strcmp(contents, data))
+    {
+      fputs("ERROR: PPD and test file are not the same.\n", stderr);
+      status = 1;
+    }
+
+    if (status)
+    {
+      if ((fp = fopen("testppdx.dat", "wb")) != NULL)
+      {
+        fwrite(data, 1, datasize, fp);
+        fclose(fp);
+        fputs("ERROR: See testppdx.dat for data from PPD.\n", stderr);
+      }
+      else
+        perror("Unable to open 'testppdx.dat'");
+    }
+
+    free(data);
+  }
+
+  printf("Encoding %ld bytes for PPD...\n", (long)contsize);
+
+  ppdxWriteData("EXData", contents, contsize);
+
+  return (1);
+}
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/examples/testppdx.ppd b/examples/testppdx.ppd
new file mode 100644 (file)
index 0000000..179b1ec
--- /dev/null
@@ -0,0 +1,121 @@
+*PPD-Adobe: "4.3"
+*%
+*% "$Id$"
+*%
+*% Test PPD file for data encoding example.
+*%
+*% This file cannot be used with any known printers.
+*%
+*% Copyright 2007-2012 by Apple Inc.
+*% Copyright 2002-2006 by Easy Software Products.
+*%
+*% These coded instructions, statements, and computer programs are the
+*% property of Apple Inc. and are protected by Federal copyright
+*% law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+*% which should have been included with this file.  If this file is
+*% file is missing or damaged, see the license at "http://www.cups.org/".
+*FormatVersion:        "4.3"
+*FileVersion:  "1.3"
+*LanguageVersion: English
+*LanguageEncoding: ISOLatin1
+*PCFileName:   "TESTPPDX.PPD"
+*Manufacturer: "Apple"
+*Product:      "(Test PPDX)"
+*cupsVersion:  1.6
+*ModelName:     "Test PPDX"
+*ShortNickName: "Test PPDX"
+*NickName:      "Test PPDX for CUPS"
+*PSVersion:    "(3010.000) 0"
+*LanguageLevel:        "3"
+*ColorDevice:  True
+*DefaultColorSpace: RGB
+*FileSystem:   False
+*Throughput:   "1"
+*LandscapeOrientation: Plus90
+*TTRasterizer: Type42
+*cupsFilter: "application/vnd.cups-raster 0 -"
+*RequiresPageRegion All: True
+
+*% For PageSize, we have put all of the translations in-line...
+*OpenUI *PageSize/Page Size: PickOne
+*OrderDependency: 10 AnySetup *PageSize
+*DefaultPageSize: Letter
+*PageSize Letter/US Letter:    "PageSize=Letter"
+*PageSize Letter.Banner/US Letter Banner: "PageSize=Letter.Banner"
+*PageSize Letter.Fullbleed/US Letter Borderless: "PageSize=Letter.Fullbleed"
+*PageSize A4/A4:               "PageSize=A4"
+*PageSize Env10/#10 Envelope:  "PageSize=Env10"
+*CloseUI: *PageSize
+
+*% For PageRegion, we have separated the translations...
+*OpenUI *PageRegion/Page Region: PickOne
+*OrderDependency: 10 AnySetup *PageRegion
+*DefaultPageRegion: Letter
+*PageRegion Letter/US Letter:  "PageRegion=Letter"
+*PageRegion Letter.Banner/US Letter Banner: "PageRegion=Letter.Fullbleed"
+*PageRegion Letter.Fullbleed/US Letter Borderless: "PageRegion=Letter.Fullbleed"
+*PageRegion A4/A4:             "PageRegion=A4"
+*PageRegion Env10/#10 Envelope:        "PageRegion=Env10"
+*CloseUI: *PageRegion
+
+*DefaultImageableArea: Letter
+*ImageableArea Letter: "18 36 594 756"
+*ImageableArea Letter.Banner:  "18 0 594 792"
+*ImageableArea Letter.Fullbleed:       "0 0 612 792"
+*ImageableArea A4:     "18 36 577 806"
+*ImageableArea Env10:  "18 36 279 648"
+
+*DefaultPaperDimension: Letter
+*PaperDimension Letter:        "612 792"
+*PaperDimension Letter.Banner: "612 792"
+*PaperDimension Letter.Fullbleed:      "612 792"
+*PaperDimension A4:    "595 842"
+*PaperDimension Env10: "297 684"
+
+*DefaultFont: Courier
+*Font AvantGarde-Book: Standard "(001.006S)" Standard ROM
+*Font AvantGarde-BookOblique: Standard "(001.006S)" Standard ROM
+*Font AvantGarde-Demi: Standard "(001.007S)" Standard ROM
+*Font AvantGarde-DemiOblique: Standard "(001.007S)" Standard ROM
+*Font Bookman-Demi: Standard "(001.004S)" Standard ROM
+*Font Bookman-DemiItalic: Standard "(001.004S)" Standard ROM
+*Font Bookman-Light: Standard "(001.004S)" Standard ROM
+*Font Bookman-LightItalic: Standard "(001.004S)" Standard ROM
+*Font Courier: Standard "(002.004S)" Standard ROM
+*Font Courier-Bold: Standard "(002.004S)" Standard ROM
+*Font Courier-BoldOblique: Standard "(002.004S)" Standard ROM
+*Font Courier-Oblique: Standard "(002.004S)" Standard ROM
+*Font Helvetica: Standard "(001.006S)" Standard ROM
+*Font Helvetica-Bold: Standard "(001.007S)" Standard ROM
+*Font Helvetica-BoldOblique: Standard "(001.007S)" Standard ROM
+*Font Helvetica-Narrow: Standard "(001.006S)" Standard ROM
+*Font Helvetica-Narrow-Bold: Standard "(001.007S)" Standard ROM
+*Font Helvetica-Narrow-BoldOblique: Standard "(001.007S)" Standard ROM
+*Font Helvetica-Narrow-Oblique: Standard "(001.006S)" Standard ROM
+*Font Helvetica-Oblique: Standard "(001.006S)" Standard ROM
+*Font NewCenturySchlbk-Bold: Standard "(001.009S)" Standard ROM
+*Font NewCenturySchlbk-BoldItalic: Standard "(001.007S)" Standard ROM
+*Font NewCenturySchlbk-Italic: Standard "(001.006S)" Standard ROM
+*Font NewCenturySchlbk-Roman: Standard "(001.007S)" Standard ROM
+*Font Palatino-Bold: Standard "(001.005S)" Standard ROM
+*Font Palatino-BoldItalic: Standard "(001.005S)" Standard ROM
+*Font Palatino-Italic: Standard "(001.005S)" Standard ROM
+*Font Palatino-Roman: Standard "(001.005S)" Standard ROM
+*Font Symbol: Special "(001.007S)" Special ROM
+*Font Times-Bold: Standard "(001.007S)" Standard ROM
+*Font Times-BoldItalic: Standard "(001.009S)" Standard ROM
+*Font Times-Italic: Standard "(001.007S)" Standard ROM
+*Font Times-Roman: Standard "(001.007S)" Standard ROM
+*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM
+*Font ZapfDingbats: Special "(001.004S)" Standard ROM
+*%
+*% End of "$Id$".
+*%
+*EXData0000: "eNqlVm1v2zYQ/hz/ipvWznLgl6T7siXrgCJ2AANBEyQpNmAtAlqiLG4SKZBU7LTIf9/dUW9Og32ZAFsieffcc88dKS2OR3AM0Zt1+ibCJxoA3EvnobJma0UJmbFwc7OEVHgBUicmVXoLci/KqpCAQznvHC9MWSmc3Smfn3WzdG2TBGYGPCJXVbqH2fIBQR+Wq5vb1cWH+9XyfRTBbNs"
+*EXData0001: "GcwTaG6zIqkrh7evgzDVk1Xb3MO7k9N3sHmCDxWRWeuk53KfSxf4paC087ZOvDLaTcF54WUptcdnoVO0KavaS9um7EBYCT6XAQhnK2n9E5hsEIc9yQ6XvUw8RkEelzKVVhQI2TAMEIXYzQGWClmoTU002L1GgmwVIpraF0ozXYoOGUkZXa0vVh/vVnO/91FA2+UqycHlpi5SyMWjhI0"
+*EXData0002: "lBq9kqKmbEl9BFCOETDwOuuHoFxAaQZQKueooljmVJRiK1NUSHL+UKhEaiQpPES599XZYrHb7eZUkLmx20U0lLsPAK7e/I2agDcME1S7vpst5aMsUM0U7kzmd5S03CeyIkVaqAujPdWm759SKB1PYAa3UqShDzNrShDcLdycHJgk3VnlWUnQcgdJXut/HCEvRqMFw62DSricSOeEfYI"
+*EXData0003: "HFGldfN5Y/djIyT85nyqzDz//WDKolgHcxE3ah6N2hDjQHj8vxkr7Y/oWhzDNYKt9spz89aOljnKo1HpZPRtBMDGzep7ODlntxcuAJfrq9XR0XFWnQfcS6KBZbJElC2SXNijo6Spwl+/nP7685cp27aVoY3A9NEesSi9Bm3ZZUopMpxTX+WDZzx6nPZRaRggCIFG5z1Iuwh0DDxQNAQ"
+*EXData0004: "OcbnJtJ9qyPpNAISHpW/rmTYOrRC4m6l53FfAuW50OzH4IBq4Y1ciVYcdUcQ/kWTc7Rib7baU0GJYIyDKUSrP2kQTeGnNgd0eEmHNoSpbSL7orPch1SyCkNkuDn0gEKC0JENLFQGcVZN8InKjYVqJCU3wovbmk3hdMoCmqybo+2Ds+h/zs5ZUhgn427c1btF/YKw488nY1p+xp8snDw"
+*EXData0005: "CM3WJ0OzASUA7kH27eSgtwNteZJqmDklRnN9ajTTYf3wHjpxeTXYkGK4F30W4zaV1lI1bm+vb8+4+Llw8LagMxm1nIZt155O3fz8s46mDVh7xYXR20kbcNqMWzKNWgDdRjsNM8/8TyIxeTwmkrIaVITze0m/9i4ekqbO6JmSVNqE/nWilMwWQrL/waMTMCwdxqT5+NVOQ4LUa7tNNJk"
+*EXData0006: "kOQfP11dTRqvb51GGZ9WXC3usl6nrpNe667v072jN8wgNn9mpMPj49V0n5t7043hwrezNTaOPmmxCacZ5QbjIf44mhwIhDsmpDFpmxSabopW7TdO1yftNxA2LZP6rifCSbL/g8Th06E/GPoWOLS30tdWQ3yKw+fu1bHCDsDTNXyPhbfAvwxF0gE="
+*EXData0007: ""
index 1776027908cc180c2641ce312d87c99b24bbe11f..0f54d3785e4d54627679203e600376f340892993 100644 (file)
@@ -957,6 +957,21 @@ are used to identify options to use for matching.</p>
 </pre>
 
 
+<h3><span class='info'>CUPS 1.4/OS X 10.6</span><a name='cupsPageSizeCategory'>cupsPageSizeCategory</a></h3>
+
+<p class="summary">*cupsPageSizeCategory name/text: "name name2 ... nameN"</p>
+
+<p>This keyword lists related paper size names that should be grouped together in the Print or Page Setup dialogs. The "name" portion of the keyword specifies the root/default size for the grouping. On OS X the grouped paper sizes are shown in a submenu of the main paper size. When omitted, sizes with the same dimensions are automatically grouped together, for example "Letter" and "Letter.Borderless".</p>
+
+<p>Example:</p>
+
+<pre class="command">
+<em>*% Specify grouping of borderless/non-borderless sizes</em>
+*cupsPageSizeCategory Letter/US Letter: "Letter Letter.Borderless"
+*cupsPageSizeCategory A4/A4: "A4 A4.Borderless"
+</pre>
+
+
 <h2 class='title'><a name='ATTRIBUTES'>General Attributes</a></h2>
 
 <h3><span class='info'>CUPS 1.3/OS X 10.5</span><a name='cupsBackSide'>cupsBackSide</a></h3>
@@ -1335,6 +1350,7 @@ the output for a specific model of printer.</p>
 *cupsModelNumber: 1234
 </pre>
 
+
 <h3><span class='info'>CUPS 1.3/OS X 10.5</span><a name='cupsPJLCharset'>cupsPJLCharset</a></h3>
 
 <p class='summary'>*cupsPJLCharset: "ISO character set name"</p>
@@ -1795,6 +1811,8 @@ the device.</p>
 
 <ul>
 
+    <li>Added <a href="#cupsPageSizeCategory"><tt>cupsPageSizeCategory</tt></a> keyword (originally defined in CUPS 1.4).</li>
+
        <li>Added <a href="#cupsMaxCopies"><tt>cupsMaxCopies</tt></a> keyword.</li>
 
        <li>Documented <a href="#JCLToPDFInterpreter"><tt>JCLToPDFInterpreter</tt></a> keyword.</li>
index bd8f459c75dec8f018235c3b3554823cb13ff225..41d944e3e29fe1714597850a849243af067b3a91 100755 (executable)
@@ -61,7 +61,7 @@ src=""
 dst=""
 dir_arg=""
 
-function gzipcp {
+gzipcp() {
        # gzipcp from to
        $gzipprog -9 <"$1" >"$2"
 }
index b5d790f8bff1577f4adf3cc92f4af9859be89c68..fd0768fd15bf7240b9df00d9ed83486f32a3298e 100644 (file)
@@ -12,7 +12,7 @@
 .\"   which should have been included with this file.  If this file is
 .\"   file is missing or damaged, see the license at "http://www.cups.org/".
 .\"
-.TH cupsd.conf 5 "CUPS" "15 February 2012" "Apple Inc."
+.TH cupsd.conf 5 "CUPS" "18 May 2012" "Apple Inc."
 .SH NAME
 cupsd.conf \- server configuration file for cups
 .SH DESCRIPTION
@@ -591,6 +591,13 @@ SSLPort
 .br
 Listens on the specified port for encrypted connections.
 .TP 5
+StrictConformance Yes
+.TP 5
+StrictConformance No
+.br
+Specifies whether the scheduler requires clients to strictly adhere to the IPP
+specifications. The default is No.
+.TP 5
 SubscriptionPrivateAccess all
 .TP 5
 SubscriptionPrivateAccess default
index 50b087247915003b62dbdc543d41ee59e6dc3f51..1acff4b4ea7f4463b4fd26b03934ef03438091d2 100644 (file)
@@ -12,7 +12,7 @@
 .\"   which should have been included with this file.  If this file is
 .\"   file is missing or damaged, see the license at "http://www.cups.org/".
 .\"
-.TH filter 7 "CUPS" "13 April 2012" "Apple Inc."
+.TH filter 7 "CUPS" "18 May 2012" "Apple Inc."
 .SH NAME
 filter \- cups file conversion filter interface
 .SH SYNOPSIS
@@ -169,6 +169,11 @@ CUPS_FILETYPE
 The type of file being printed: "job-sheet" for a banner page and "document"
 for a regular print file.
 .TP 5
+CUPS_MAX_MESSAGE
+.br
+The maximum size of a message sent to stderr, including any leading prefix and
+the trailing newline.
+.TP 5
 CUPS_SERVERROOT
 .br
 The root directory of the server.
index 00a6df7f9a4cef3fc43ec01a09e533154fcb42c3..0d6452ea424269cb70f1d4bea66cbb4433114cdb 100644 (file)
@@ -11,7 +11,7 @@
 .\"   which should have been included with this file.  If this file is
 .\"   file is missing or damaged, see the license at "http://www.cups.org/".
 .\"
-.TH ipptoolfile 5 "CUPS" "14 March 2012" "Apple Inc."
+.TH ipptoolfile 5 "CUPS" "11 May 2012" "Apple Inc."
 .SH NAME
 ipptoolfile \- ipptool file format
 
@@ -266,6 +266,10 @@ Requires the EXPECT attribute to be in the specified group tag.
 OF-TYPE tag[,tag,...]
 Requires the EXPECT attribute to use the specified value tag(s).
 .TP 5
+REPEAT-LIMIT number
+.br
+Specifies the maximum number of times to repeat. The default value is 1000.
+.TP 5
 REPEAT-MATCH
 .TP 5
 REPEAT-NO-MATCH
@@ -325,6 +329,10 @@ Makes the STATUS apply only if the specified variable is defined.
 IF-NOT-DEFINED variable-name
 Makes the STATUS apply only if the specified variable is not defined.
 .TP 5
+REPEAT-LIMIT number
+.br
+Specifies the maximum number of times to repeat. The default value is 1000.
+.TP 5
 REPEAT-MATCH
 .TP 5
 REPEAT-NO-MATCH
index 8f1f4a106d8480380a72109186d92ebd13d8a033..6dedcaf5b991d1ab627472ad6ae1606fd0c87336 100644 (file)
@@ -472,6 +472,7 @@ f 0444 root sys $DATADIR/ipptool/print-job.test test/print-job.test
 f 0444 root sys $DATADIR/ipptool test/document-*.p*
 f 0444 root sys $DATADIR/ipptool test/ipp-*.test
 f 0444 root sys $DATADIR/ipptool test/onepage-*.p*
+f 0444 root sys $DATADIR/ipptool test/testfile.*
 f 0444 root sys $DATADIR/ipptool/color.jpg test/color.jpg
 f 0444 root sys $DATADIR/ipptool/gray.jpg test/gray.jpg
 
index 2fa6090f5157b09ac6c1245945caaec2171e287f..d6035e0aa19773bdea880bc836c93d21a1bb12cd 100644 (file)
@@ -21,6 +21,7 @@ CUPSDOBJS =   \
                cert.o \
                classes.o \
                client.o \
+               colorman.o \
                conf.o \
                dirsvc.o \
                env.o \
index 31d12cc619db7111a0967b161b6a3ff43395f90a..fcc4d814c912276fa5491c50f0439ac044fcd0a9 100644 (file)
@@ -4026,9 +4026,19 @@ valid_host(cupsd_client_t *con)          /* I - Client connection */
   * Check if the hostname is something.local (Bonjour); if so, allow it.
   */
 
-  if ((end = strrchr(host, '.')) != NULL &&
-      (!_cups_strcasecmp(end, ".local") || !_cups_strncasecmp(end, ".local:", 7) ||
-       !_cups_strcasecmp(end, ".local.") || !_cups_strncasecmp(end, ".local.:", 8)))
+  if ((end = strrchr(host, '.')) != NULL && end > host &&
+      (!end[1] || end[1] == ':'))
+  {
+   /*
+    * "." on end, work back to second-to-last "."...
+    */
+    for (end --; end > host && *end != '.'; end --);
+  }
+
+  if (end && (!_cups_strcasecmp(end, ".local") ||
+             !_cups_strncasecmp(end, ".local:", 7) ||
+             !_cups_strcasecmp(end, ".local.") ||
+             !_cups_strncasecmp(end, ".local.:", 8)))
     return (1);
 #endif /* HAVE_DNSSD */
 
diff --git a/scheduler/colorman.c b/scheduler/colorman.c
new file mode 100644 (file)
index 0000000..c662a2c
--- /dev/null
@@ -0,0 +1,1505 @@
+/*
+ * "$Id$"
+ *
+ *   Color management routines for the CUPS scheduler.
+ *
+ *   Copyright 2007-2012 by Apple Inc.
+ *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ *   These coded instructions, statements, and computer programs are the
+ *   property of Apple Inc. and are protected by Federal copyright
+ *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ *   which should have been included with this file.  If this file is
+ *   file is missing or damaged, see the license at "http://www.cups.org/".
+ *
+ *   Original DBUS/colord code is Copyright 2011 Red Hat, Inc.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *   Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ *   Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ *   COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ *   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ *   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ *   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ *   OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Contents:
+ *
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "cupsd.h"
+#include <cups/ppd-private.h>
+
+#ifdef __APPLE__
+#  include <ApplicationServices/ApplicationServices.h>
+extern CFUUIDRef ColorSyncCreateUUIDFromUInt32(unsigned id);
+#  include <CoreFoundation/CoreFoundation.h>
+#elif defined(HAVE_DBUS)
+#  include <dbus/dbus.h>
+
+/*
+ * Defines used by colord. See the reference docs for further details:
+ *
+ *   http://colord.hughsie.com/api/ref-dbus.html
+ */
+
+#  define COLORD_SCOPE_NORMAL  "normal"
+                                       /* System scope */
+#  define COLORD_SCOPE_TEMP    "temp"  /* Process scope */
+#  define COLORD_SCOPE_DISK    "disk"  /* Lives forever, as stored in DB */
+
+#  define COLORD_RELATION_SOFT "soft"  /* Mapping is not default */
+#  define COLORD_RELATION_HARD "hard"  /* Explicitly mapped profile */
+
+#  define COLORD_SPACE_RGB     "rgb"   /* RGB colorspace */
+#  define COLORD_SPACE_CMYK    "cmyk"  /* CMYK colorspace */
+#  define COLORD_SPACE_GRAY    "gray"  /* Gray colorspace */
+#  define COLORD_SPACE_UNKNOWN "unknown"
+                                       /* Unknown colorspace */
+
+#  define COLORD_MODE_PHYSICAL "physical"
+                                       /* Actual device */
+#  define COLORD_MODE_VIRTUAL  "virtual"
+                                       /* Virtual device with no hardware */
+
+#  define COLORD_KIND_PRINTER  "printer"
+                                       /* printing output device */
+
+#  define COLORD_DBUS_MSG(p,m) dbus_message_new_method_call(\
+                                       "org.freedesktop.ColorManager", (p),\
+                                        "org.freedesktop.ColorManager", (m))
+                                        /* Macro to make new colord messages */
+#  define COLORD_DBUS_PATH     "/org/freedesktop/ColorManager"
+                                       /* Path for color management system */
+#  define COLORD_DBUS_TIMEOUT  5000    /* Timeout for connecting to colord in ms */
+#endif /* __APPLE__ */
+
+
+/*
+ * Local globals...
+ */
+
+#if !defined(__APPLE__) && defined(HAVE_DBUS)
+static DBusConnection *colord_con = NULL;
+                                       /* DBUS connection for colord */
+#endif /* !__APPLE__ && HAVE_DBUS */
+
+
+/*
+ * Local functions...
+ */
+
+#ifdef __APPLE__
+static void    apple_init_profile(ppd_file_t *ppd, cups_array_t *languages,
+                                   CFMutableDictionaryRef profile,
+                                  unsigned id, const char *name,
+                                  const char *text, const char *iccfile);
+static void    apple_register_profiles(cupsd_printer_t *p);
+static void    apple_unregister_profiles(cupsd_printer_t *p);
+
+#elif defined(HAVE_DBUS)
+static void    colord_create_device(cupsd_printer_t *p, ppd_file_t *ppd,
+                                    cups_array_t *profiles,
+                                    const char *colorspace, char **format,
+                                    const char *relation, const char *scope);
+static void    colord_create_profile(cups_array_t *profiles,
+                                     const char *printer_name,
+                                     const char *qualifier,
+                                     const char *colorspace,
+                                     char **format, const char *iccfile,
+                                     const char *scope);
+static void    colord_delete_device(const char *device_id);
+static void    colord_device_add_profile(const char *device_path,
+                                         const char *profile_path,
+                                         const char *relation);
+static void    colord_dict_add_strings(DBusMessageIter *dict,
+                                       const char *key, const char *value);
+static char    *colord_find_device(const char *device_id);
+static void    colord_get_qualifier_format(ppd_file_t *ppd, char *format[3]);
+static void    colord_register_printer(cupsd_printer_t *p);
+static void    colord_unregister_printer(cupsd_printer_t *p);
+#endif /* __APPLE__ */
+
+
+/*
+ * 'cupsdRegisterColor()' - Register vendor color profiles in a PPD file.
+ */
+
+void
+cupsdRegisterColor(cupsd_printer_t *p) /* I - Printer */
+{
+#ifdef __APPLE__
+  apple_unregister_profiles(p);
+  apple_register_profiles(p);
+
+#elif defined(HAVE_DBUS)
+  colord_unregister_printer(p);
+  colord_register_printer(p);
+#endif /* __APPLE__ */
+}
+
+
+/*
+ * 'cupsdStartColor()' - Initialize color management.
+ */
+
+void
+cupsdStartColor(void)
+{
+#if !defined(__APPLE__) && defined(HAVE_DBUS)
+  cupsd_printer_t      *p;             /* Current printer */
+
+
+  colord_con = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+
+  for (p = (cupsd_printer_t *)cupsArrayFirst(Printers);
+       p;
+       p = (cupsd_printer_t *)cupsArrayNext(Printers))
+    cupsdRegisterColor(p);
+#endif /* !__APPLE__ && HAVE_DBUS */
+}
+
+
+/*
+ * 'cupsdStopColor()' - Shutdown color management.
+ */
+
+void
+cupsdStopColor(void)
+{
+#if !defined(__APPLE__) && defined(HAVE_DBUS)
+  dbus_connection_unref(colord_con);
+  colord_con = NULL;
+#endif /* !__APPLE__ && HAVE_DBUS */
+}
+
+
+/*
+ * 'cupsdUnregisterColor()' - Unregister vendor color profiles in a PPD file.
+ */
+
+void
+cupsdUnregisterColor(cupsd_printer_t *p)/* I - Printer */
+{
+#ifdef __APPLE__
+  apple_unregister_profiles(p);
+
+#elif defined(HAVE_DBUS)
+  colord_unregister_printer(p);
+#endif /* __APPLE__ */
+}
+
+
+#ifdef __APPLE__
+/*
+ * 'apple_init_profile()' - Initialize a color profile.
+ */
+
+static void
+apple_init_profile(
+    ppd_file_t             *ppd,       /* I - PPD file */
+    cups_array_t          *languages,  /* I - Languages in the PPD file */
+    CFMutableDictionaryRef profile,    /* I - Profile dictionary */
+    unsigned               id,         /* I - Profile ID */
+    const char             *name,      /* I - Profile name */
+    const char             *text,      /* I - Profile UI text */
+    const char             *iccfile)   /* I - ICC filename */
+{
+  CFURLRef             url;            /* URL for profile filename */
+  CFMutableDictionaryRef dict;         /* Dictionary for name */
+  char                 *language;      /* Current language */
+  ppd_attr_t           *attr;          /* Profile attribute */
+  CFStringRef          cflang,         /* Language string */
+                       cftext;         /* Localized text */
+
+
+  (void)id;
+
+ /*
+  * Build the profile name dictionary...
+  */
+
+  dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+                                  &kCFTypeDictionaryKeyCallBacks,
+                                  &kCFTypeDictionaryValueCallBacks);
+  if (!dict)
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize profile \"%s\".",
+                    iccfile);
+    return;
+  }
+
+  cftext = CFStringCreateWithCString(kCFAllocatorDefault, text,
+                                    kCFStringEncodingUTF8);
+
+  if (cftext)
+  {
+    CFDictionarySetValue(dict, CFSTR("en_US"), cftext);
+    CFRelease(cftext);
+  }
+
+  if (languages)
+  {
+   /*
+    * Find localized names for the color profiles...
+    */
+
+    cupsArraySave(ppd->sorted_attrs);
+
+    for (language = (char *)cupsArrayFirst(languages);
+        language;
+        language = (char *)cupsArrayNext(languages))
+    {
+      if (iccfile)
+      {
+        if ((attr = _ppdLocalizedAttr(ppd, "cupsICCProfile", name,
+                                     language)) == NULL)
+         attr = _ppdLocalizedAttr(ppd, "APTiogaProfile", name, language);
+      }
+      else
+        attr = _ppdLocalizedAttr(ppd, "ColorModel", name, language);
+
+      if (attr && attr->text[0])
+      {
+       cflang = CFStringCreateWithCString(kCFAllocatorDefault, language,
+                                          kCFStringEncodingUTF8);
+       cftext = CFStringCreateWithCString(kCFAllocatorDefault, attr->text,
+                                          kCFStringEncodingUTF8);
+
+        if (cflang && cftext)
+         CFDictionarySetValue(dict, cflang, cftext);
+
+        if (cflang)
+         CFRelease(cflang);
+
+        if (cftext)
+         CFRelease(cftext);
+      }
+    }
+
+    cupsArrayRestore(ppd->sorted_attrs);
+  }
+
+ /*
+  * Fill in the profile data...
+  */
+
+ if (iccfile)
+ {
+    url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
+                                                 (const UInt8 *)iccfile,
+                                                  strlen(iccfile), false);
+
+    if (url)
+    {
+      CFDictionarySetValue(profile, kColorSyncDeviceProfileURL, url);
+      CFRelease(url);
+    }
+  }
+
+  CFDictionarySetValue(profile, kColorSyncDeviceModeDescriptions, dict);
+  CFRelease(dict);
+}
+
+
+/*
+ * 'apple_register_profiles()' - Register color profiles for a printer.
+ */
+
+static void
+apple_register_profiles(
+    cupsd_printer_t *p)                        /* I - Printer */
+{
+  int                  i;              /* Looping var */
+  char                 ppdfile[1024],  /* PPD filename */
+                       iccfile[1024],  /* ICC filename */
+                       selector[PPD_MAX_NAME];
+                                       /* Profile selection string */
+  ppd_file_t           *ppd;           /* PPD file */
+  ppd_attr_t           *attr,          /* Profile attributes */
+                       *profileid_attr,/* cupsProfileID attribute */
+                       *q1_attr,       /* ColorModel (or other) qualifier */
+                       *q2_attr,       /* MediaType (or other) qualifier */
+                       *q3_attr;       /* Resolution (or other) qualifier */
+  char                 q_keyword[PPD_MAX_NAME];
+                                       /* Qualifier keyword */
+  const char           *q1_choice,     /* ColorModel (or other) choice */
+                       *q2_choice,     /* MediaType (or other) choice */
+                       *q3_choice;     /* Resolution (or other) choice */
+  ppd_option_t         *cm_option;     /* Color model option */
+  ppd_choice_t         *cm_choice;     /* Color model choice */
+  int                  num_profiles;   /* Number of profiles */
+  OSStatus             error = 0;      /* Last error */
+  unsigned             device_id,      /* Printer device ID */
+                       profile_id = 0, /* Profile ID */
+                       default_profile_id = 0;
+                                       /* Default profile ID */
+  CFMutableDictionaryRef device_name;  /* Printer device name dictionary */
+  CFStringRef          printer_name;   /* Printer name string */
+  cups_array_t         *languages;     /* Languages array */
+  CFMutableDictionaryRef profiles,     /* Dictionary of profiles */
+                       profile;        /* Current profile info dictionary */
+  CFStringRef          dict_key;       /* Key in factory profile dictionary */
+
+
+ /*
+  * Make sure ColorSync is available...
+  */
+
+  if (ColorSyncRegisterDevice == NULL)
+    return;
+
+ /*
+  * Try opening the PPD file for this printer...
+  */
+
+  snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name);
+  if ((ppd = _ppdOpenFile(ppdfile, _PPD_LOCALIZATION_ICC_PROFILES)) == NULL)
+    return;
+
+ /*
+  * See if we have any profiles...
+  */
+
+  for (num_profiles = 0, attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
+       attr;
+       attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
+    if (attr->spec[0] && attr->value && attr->value[0])
+    {
+      if (attr->value[0] != '/')
+       snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir,
+                attr->value);
+      else
+       strlcpy(iccfile, attr->value, sizeof(iccfile));
+
+      if (access(iccfile, 0))
+      {
+        cupsdLogMessage(CUPSD_LOG_ERROR,
+                        "%s: ICC Profile \"%s\" does not exist.", p->name,
+                        iccfile);
+        cupsdSetPrinterReasons(p, "+cups-missing-filter-warning");
+       continue;
+      }
+
+      num_profiles ++;
+    }
+
+ /*
+  * Create a dictionary for the factory profiles...
+  */
+
+  profiles = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+                                      &kCFTypeDictionaryKeyCallBacks,
+                                      &kCFTypeDictionaryValueCallBacks);
+  if (!profiles)
+  {
+    cupsdLogMessage(CUPSD_LOG_ERROR,
+                   "Unable to allocate memory for factory profiles.");
+    ppdClose(ppd);
+    return;
+  }
+
+ /*
+  * If we have profiles, add them...
+  */
+
+  if (num_profiles > 0)
+  {
+   /*
+    * For CUPS PPDs, figure out the default profile selector values...
+    */
+
+    if ((attr = ppdFindAttr(ppd, "cupsICCQualifier1", NULL)) != NULL &&
+       attr->value && attr->value[0])
+    {
+      snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
+      q1_attr = ppdFindAttr(ppd, q_keyword, NULL);
+    }
+    else if ((q1_attr = ppdFindAttr(ppd, "DefaultColorModel", NULL)) == NULL)
+      q1_attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL);
+
+    if (q1_attr && q1_attr->value && q1_attr->value[0])
+      q1_choice = q1_attr->value;
+    else
+      q1_choice = "";
+
+    if ((attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL &&
+       attr->value && attr->value[0])
+    {
+      snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
+      q2_attr = ppdFindAttr(ppd, q_keyword, NULL);
+    }
+    else
+      q2_attr = ppdFindAttr(ppd, "DefaultMediaType", NULL);
+
+    if (q2_attr && q2_attr->value && q2_attr->value[0])
+      q2_choice = q2_attr->value;
+    else
+      q2_choice = NULL;
+
+    if ((attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL &&
+       attr->value && attr->value[0])
+    {
+      snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
+      q3_attr = ppdFindAttr(ppd, q_keyword, NULL);
+    }
+    else
+      q3_attr = ppdFindAttr(ppd, "DefaultResolution", NULL);
+
+    if (q3_attr && q3_attr->value && q3_attr->value[0])
+      q3_choice = q3_attr->value;
+    else
+      q3_choice = NULL;
+
+   /*
+    * Loop through the profiles listed in the PPD...
+    */
+
+    languages = _ppdGetLanguages(ppd);
+
+    for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
+        attr;
+        attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
+      if (attr->spec[0] && attr->value && attr->value[0])
+      {
+       /*
+        * Add this profile...
+       */
+
+        if (attr->value[0] != '/')
+         snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir,
+                  attr->value);
+        else
+         strlcpy(iccfile, attr->value, sizeof(iccfile));
+
+        if (_cupsFileCheck(iccfile, _CUPS_FILE_CHECK_FILE, !RunUser,
+                          cupsdLogFCMessage, p))
+         continue;
+
+       cupsArraySave(ppd->sorted_attrs);
+
+       if ((profileid_attr = ppdFindAttr(ppd, "cupsProfileID",
+                                         attr->spec)) != NULL &&
+           profileid_attr->value && isdigit(profileid_attr->value[0] & 255))
+         profile_id = (unsigned)strtoul(profileid_attr->value, NULL, 10);
+       else
+         profile_id = _ppdHashName(attr->spec);
+
+       cupsArrayRestore(ppd->sorted_attrs);
+
+       profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+                                           &kCFTypeDictionaryKeyCallBacks,
+                                           &kCFTypeDictionaryValueCallBacks);
+       if (!profile)
+       {
+         cupsdLogMessage(CUPSD_LOG_ERROR,
+                         "Unable to allocate memory for color profile.");
+         CFRelease(profiles);
+         ppdClose(ppd);
+         return;
+       }
+
+       apple_init_profile(ppd, languages, profile, profile_id, attr->spec,
+                          attr->text[0] ? attr->text : attr->spec, iccfile);
+
+       dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
+                                           CFSTR("%u"), profile_id);
+       if (dict_key)
+       {
+         CFDictionarySetValue(profiles, dict_key, profile);
+         CFRelease(dict_key);
+       }
+
+       CFRelease(profile);
+
+       /*
+        * See if this is the default profile...
+       */
+
+        if (!default_profile_id && q1_choice && q2_choice && q3_choice)
+       {
+         snprintf(selector, sizeof(selector), "%s.%s.%s", q1_choice, q2_choice,
+                  q3_choice);
+         if (!strcmp(selector, attr->spec))
+           default_profile_id = profile_id;
+       }
+
+        if (!default_profile_id && q1_choice && q2_choice)
+       {
+         snprintf(selector, sizeof(selector), "%s.%s.", q1_choice, q2_choice);
+         if (!strcmp(selector, attr->spec))
+           default_profile_id = profile_id;
+       }
+
+        if (!default_profile_id && q1_choice && q3_choice)
+       {
+         snprintf(selector, sizeof(selector), "%s..%s", q1_choice, q3_choice);
+         if (!strcmp(selector, attr->spec))
+           default_profile_id = profile_id;
+       }
+
+        if (!default_profile_id && q1_choice)
+       {
+         snprintf(selector, sizeof(selector), "%s..", q1_choice);
+         if (!strcmp(selector, attr->spec))
+           default_profile_id = profile_id;
+       }
+
+        if (!default_profile_id && q2_choice && q3_choice)
+       {
+         snprintf(selector, sizeof(selector), ".%s.%s", q2_choice, q3_choice);
+         if (!strcmp(selector, attr->spec))
+           default_profile_id = profile_id;
+       }
+
+        if (!default_profile_id && q2_choice)
+       {
+         snprintf(selector, sizeof(selector), ".%s.", q2_choice);
+         if (!strcmp(selector, attr->spec))
+           default_profile_id = profile_id;
+       }
+
+        if (!default_profile_id && q3_choice)
+       {
+         snprintf(selector, sizeof(selector), "..%s", q3_choice);
+         if (!strcmp(selector, attr->spec))
+           default_profile_id = profile_id;
+       }
+      }
+
+    _ppdFreeLanguages(languages);
+  }
+  else if ((cm_option = ppdFindOption(ppd, "ColorModel")) != NULL)
+  {
+   /*
+    * Extract profiles from ColorModel option...
+    */
+
+    const char *profile_name;          /* Name of generic profile */
+
+
+    num_profiles = cm_option->num_choices;
+
+    for (i = cm_option->num_choices, cm_choice = cm_option->choices;
+         i > 0;
+        i --, cm_choice ++)
+    {
+      if (!strcmp(cm_choice->choice, "Gray") ||
+          !strcmp(cm_choice->choice, "Black"))
+        profile_name = "Gray";
+      else if (!strcmp(cm_choice->choice, "RGB") ||
+               !strcmp(cm_choice->choice, "CMY"))
+        profile_name = "RGB";
+      else if (!strcmp(cm_choice->choice, "CMYK") ||
+               !strcmp(cm_choice->choice, "KCMY"))
+        profile_name = "CMYK";
+      else
+        profile_name = "DeviceN";
+
+      snprintf(selector, sizeof(selector), "%s..", profile_name);
+      profile_id = _ppdHashName(selector);
+
+      profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+                                         &kCFTypeDictionaryKeyCallBacks,
+                                         &kCFTypeDictionaryValueCallBacks);
+      if (!profile)
+      {
+       cupsdLogMessage(CUPSD_LOG_ERROR,
+                       "Unable to allocate memory for color profile.");
+       CFRelease(profiles);
+       ppdClose(ppd);
+       return;
+      }
+
+      apple_init_profile(ppd, NULL, profile, profile_id, cm_choice->choice,
+                         cm_choice->text, NULL);
+
+      dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
+                                          CFSTR("%u"), profile_id);
+      if (dict_key)
+      {
+       CFDictionarySetValue(profiles, dict_key, profile);
+       CFRelease(dict_key);
+      }
+
+      CFRelease(profile);
+
+      if (cm_choice->marked)
+        default_profile_id = profile_id;
+    }
+  }
+  else
+  {
+   /*
+    * Use the default colorspace...
+    */
+
+    attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL);
+
+    num_profiles = (attr && ppd->colorspace == PPD_CS_GRAY) ? 1 : 2;
+
+   /*
+    * Add the grayscale profile first.  We always have a grayscale profile.
+    */
+
+    profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+                                       &kCFTypeDictionaryKeyCallBacks,
+                                       &kCFTypeDictionaryValueCallBacks);
+
+    if (!profile)
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR,
+                      "Unable to allocate memory for color profile.");
+      CFRelease(profiles);
+      ppdClose(ppd);
+      return;
+    }
+
+    profile_id = _ppdHashName("Gray..");
+    apple_init_profile(ppd, NULL, profile, profile_id, "Gray", "Gray", NULL);
+
+    dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"),
+                                        profile_id);
+    if (dict_key)
+    {
+      CFDictionarySetValue(profiles, dict_key, profile);
+      CFRelease(dict_key);
+    }
+
+    CFRelease(profile);
+
+   /*
+    * Then add the RGB/CMYK/DeviceN color profile...
+    */
+
+    profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+                                       &kCFTypeDictionaryKeyCallBacks,
+                                       &kCFTypeDictionaryValueCallBacks);
+
+    if (!profile)
+    {
+      cupsdLogMessage(CUPSD_LOG_ERROR,
+                      "Unable to allocate memory for color profile.");
+      CFRelease(profiles);
+      ppdClose(ppd);
+      return;
+    }
+
+    switch (ppd->colorspace)
+    {
+      default :
+      case PPD_CS_RGB :
+      case PPD_CS_CMY :
+          profile_id = _ppdHashName("RGB..");
+          apple_init_profile(ppd, NULL, profile, profile_id, "RGB", "RGB",
+                            NULL);
+          break;
+
+      case PPD_CS_RGBK :
+      case PPD_CS_CMYK :
+          profile_id = _ppdHashName("CMYK..");
+          apple_init_profile(ppd, NULL, profile, profile_id, "CMYK", "CMYK",
+                            NULL);
+          break;
+
+      case PPD_CS_GRAY :
+          if (attr)
+            break;
+
+      case PPD_CS_N :
+          profile_id = _ppdHashName("DeviceN..");
+          apple_init_profile(ppd, NULL, profile, profile_id, "DeviceN",
+                            "DeviceN", NULL);
+          break;
+    }
+
+    if (CFDictionaryGetCount(profile) > 0)
+    {
+      dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
+                                          CFSTR("%u"), profile_id);
+      if (dict_key)
+      {
+        CFDictionarySetValue(profiles, dict_key, profile);
+        CFRelease(dict_key);
+      }
+    }
+
+    CFRelease(profile);
+  }
+
+  if (num_profiles > 0)
+  {
+   /*
+    * Make sure we have a default profile ID...
+    */
+
+    if (!default_profile_id)
+      default_profile_id = profile_id; /* Last profile */
+
+    dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"),
+                                        default_profile_id);
+    if (dict_key)
+    {
+      CFDictionarySetValue(profiles, kColorSyncDeviceDefaultProfileID,
+                           dict_key);
+      CFRelease(dict_key);
+    }
+
+   /*
+    * Get the device ID hash and pathelogical name dictionary.
+    */
+
+    cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for \"%s\"",
+                   p->name);
+
+    device_id    = _ppdHashName(p->name);
+    device_name  = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+                                            &kCFTypeDictionaryKeyCallBacks,
+                                            &kCFTypeDictionaryValueCallBacks);
+    printer_name = CFStringCreateWithCString(kCFAllocatorDefault,
+                                             p->name, kCFStringEncodingUTF8);
+
+    if (device_name && printer_name)
+    {
+     /*
+      * Register the device with ColorSync...
+      */
+
+      CFTypeRef                deviceDictKeys[] =
+      {                                        /* Device keys */
+        kColorSyncDeviceDescriptions,
+       kColorSyncFactoryProfiles,
+       kColorSyncDeviceUserScope,
+       kColorSyncDeviceHostScope
+      };
+      CFTypeRef        deviceDictVals[] =
+      {                                        /* Device values */
+        device_name,
+       profiles,
+       kCFPreferencesAnyUser,
+       kCFPreferencesCurrentHost
+      };
+      CFDictionaryRef  deviceDict;     /* Device dictionary */
+      CFUUIDRef                deviceUUID;     /* Device UUID */
+
+      CFDictionarySetValue(device_name, CFSTR("en_US"), printer_name);
+
+      deviceDict = CFDictionaryCreate(kCFAllocatorDefault,
+                                     (const void **)deviceDictKeys,
+                                     (const void **)deviceDictVals,
+                                     sizeof(deviceDictKeys) /
+                                         sizeof(deviceDictKeys[0]),
+                                     &kCFTypeDictionaryKeyCallBacks,
+                                     &kCFTypeDictionaryValueCallBacks);
+      deviceUUID = ColorSyncCreateUUIDFromUInt32(device_id);
+
+      if (!deviceDict || !deviceUUID ||
+         !ColorSyncRegisterDevice(kColorSyncPrinterDeviceClass, deviceUUID,
+                                  deviceDict))
+       error = 1001;
+
+      if (deviceUUID)
+        CFRelease(deviceUUID);
+
+      if (deviceDict)
+        CFRelease(deviceDict);
+    }
+    else
+      error = 1000;
+
+   /*
+    * Clean up...
+    */
+
+    if (error != noErr)
+      cupsdLogMessage(CUPSD_LOG_ERROR,
+                     "Unable to register ICC color profiles for \"%s\": %d",
+                     p->name, (int)error);
+
+    if (printer_name)
+      CFRelease(printer_name);
+
+    if (device_name)
+      CFRelease(device_name);
+  }
+
+ /*
+  * Free any memory we used...
+  */
+
+  CFRelease(profiles);
+
+  ppdClose(ppd);
+}
+
+
+/*
+ * 'apple_unregister_profiles()' - Remove color profiles for the specified
+ *                                 printer.
+ */
+
+static void
+apple_unregister_profiles(
+    cupsd_printer_t *p)                        /* I - Printer */
+{
+ /*
+  * Make sure ColorSync is available...
+  */
+
+  if (ColorSyncUnregisterDevice != NULL)
+  {
+    CFUUIDRef deviceUUID;              /* Device UUID */
+
+    deviceUUID = ColorSyncCreateUUIDFromUInt32(_ppdHashName(p->name));
+    if (deviceUUID)
+    {
+      ColorSyncUnregisterDevice(kColorSyncPrinterDeviceClass, deviceUUID);
+      CFRelease(deviceUUID);
+    }
+  }
+}
+
+
+#elif defined(HAVE_DBUS)
+/*
+ * 'colord_create_device()' - Create a device and register profiles.
+ */
+
+static void
+colord_create_device(
+    cupsd_printer_t *p,                        /* I - Printer */
+    ppd_file_t      *ppd,              /* I - PPD file */
+    cups_array_t    *profiles,         /* I - Profiles array */
+    const char      *colorspace,       /* I - Device colorspace, e.g. 'rgb' */
+    char            **format,          /* I - Device qualifier format */
+    const char      *relation,         /* I - Profile relation, either 'soft'
+                                              or 'hard' */
+    const char      *scope)            /* I - The scope of the device, e.g.
+                                              'normal', 'temp' or 'disk' */
+{
+  DBusMessage  *message = NULL;        /* D-Bus request */
+  DBusMessage  *reply = NULL;          /* D-Bus reply */
+  DBusMessageIter args;                        /* D-Bus method arguments */
+  DBusMessageIter dict;                        /* D-Bus method arguments */
+  DBusError    error;                  /* D-Bus error */
+  const char   *device_path;           /* Device object path */
+  const char   *profile_path;          /* Profile path */
+  char         *default_profile_path = NULL;
+                                       /* Default profile path */
+  char         device_id[1024];        /* Device ID as understood by colord */
+  char         format_str[1024];       /* Qualifier format as a string */
+
+
+ /*
+  * Create the device...
+  */
+
+  snprintf(device_id, sizeof(device_id), "cups-%s", p->name);
+  device_path = device_id;
+
+  message = COLORD_DBUS_MSG(COLORD_DBUS_PATH, "CreateDevice");
+
+  dbus_message_iter_init_append(message, &args);
+  dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_path);
+  dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope);
+
+  snprintf(format_str, sizeof(format_str), "%s.%s.%s", format[0], format[1],
+           format[2]);
+
+  dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{ss}", &dict);
+  colord_dict_add_strings(&dict, "Colorspace", colorspace);
+  colord_dict_add_strings(&dict, "Mode", COLORD_MODE_PHYSICAL);
+  if (ppd->manufacturer)
+    colord_dict_add_strings(&dict, "Vendor", ppd->manufacturer);
+  if (ppd->modelname)
+    colord_dict_add_strings(&dict, "Model", ppd->modelname);
+  if (p->sanitized_device_uri)
+    colord_dict_add_strings(&dict, "Serial", p->sanitized_device_uri);
+  colord_dict_add_strings(&dict, "Format", format_str);
+  colord_dict_add_strings(&dict, "Kind", COLORD_KIND_PRINTER);
+  dbus_message_iter_close_container(&args, &dict);
+
+ /*
+  * Send the CreateDevice request synchronously...
+  */
+
+  dbus_error_init(&error);
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateDevice(%s,%s)", device_id,
+                  scope);
+  reply = dbus_connection_send_with_reply_and_block(colord_con, message,
+                                                    COLORD_DBUS_TIMEOUT,
+                                                    &error);
+  if (!reply)
+  {
+    cupsdLogMessage(CUPSD_LOG_WARN, "CreateDevice failed: %s:%s", error.name,
+                    error.message);
+    dbus_error_free(&error);
+    goto out;
+  }
+
+ /*
+  * Get reply data...
+  */
+
+  dbus_message_iter_init(reply, &args);
+  if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
+  {
+    cupsdLogMessage(CUPSD_LOG_WARN,
+                    "CreateDevice failed: Incorrect reply type.");
+    goto out;
+  }
+
+  dbus_message_iter_get_basic(&args, &device_path);
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "Created device \"%s\".", device_path);
+
+ /*
+  * Add profiles...
+  */
+
+  for (profile_path = cupsArrayFirst(profiles);
+       profile_path;
+       profile_path = cupsArrayNext(profiles))
+  {
+    colord_device_add_profile(device_path, profile_path, relation);
+  }
+
+out:
+
+  if (default_profile_path)
+    free(default_profile_path);
+
+  if (message)
+    dbus_message_unref(message);
+
+  if (reply)
+    dbus_message_unref(reply);
+}
+
+
+/*
+ * 'colord_create_profile()' - Create a color profile for a printer.
+ */
+
+static void
+colord_create_profile(
+    cups_array_t *profiles,            /* I - Profiles array */
+    const char   *printer_name,                /* I - Printer name */
+    const char   *qualifier,           /* I - Profile qualifier */
+    const char   *colorspace,          /* I - Profile colorspace */
+    char         **format,             /* I - Profile qualifier format */
+    const char   *iccfile,             /* I - ICC filename */
+    const char   *scope)               /* I - The scope of the profile, e.g.
+                                              'normal', 'temp' or 'disk' */
+{
+  DBusMessage  *message = NULL;        /* D-Bus request */
+  DBusMessage  *reply = NULL;          /* D-Bus reply */
+  DBusMessageIter args;                        /* D-Bus method arguments */
+  DBusMessageIter dict;                        /* D-Bus method arguments */
+  DBusError    error;                  /* D-Bus error */
+  char         *idstr;                 /* Profile ID string */
+  size_t       idstrlen;               /* Profile ID allocated length */
+  const char   *profile_path;          /* Device object path */
+  char         format_str[1024];       /* Qualifier format as a string */
+
+
+ /*
+  * Create the profile...
+  */
+
+  message = COLORD_DBUS_MSG(COLORD_DBUS_PATH, "CreateProfile");
+
+  idstrlen = strlen(printer_name) + 1 + strlen(qualifier) + 1;
+  if ((idstr = malloc(idstrlen)) == NULL)
+    goto out;
+  snprintf(idstr, idstrlen, "%s-%s", printer_name, qualifier);
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "Using profile ID \"%s\".", idstr);
+
+  dbus_message_iter_init_append(message, &args);
+  dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &idstr);
+  dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &scope);
+
+  snprintf(format_str, sizeof(format_str), "%s.%s.%s", format[0], format[1],
+           format[2]);
+
+  dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{ss}", &dict);
+  colord_dict_add_strings(&dict, "Qualifier", qualifier);
+  colord_dict_add_strings(&dict, "Format", format_str);
+  colord_dict_add_strings(&dict, "Colorspace", colorspace);
+  if (iccfile)
+    colord_dict_add_strings(&dict, "Filename", iccfile);
+  dbus_message_iter_close_container(&args, &dict);
+
+ /*
+  * Send the CreateProfile request synchronously...
+  */
+
+  dbus_error_init(&error);
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling CreateProfile(%s,%s)", idstr,
+                  scope);
+  reply = dbus_connection_send_with_reply_and_block(colord_con, message,
+                                                    COLORD_DBUS_TIMEOUT,
+                                                    &error);
+  if (!reply)
+  {
+    cupsdLogMessage(CUPSD_LOG_WARN, "CreateProfile failed: %s:%s", error.name,
+                    error.message);
+    dbus_error_free(&error);
+    goto out;
+  }
+
+ /*
+  * Get reply data...
+  */
+
+  dbus_message_iter_init(reply, &args);
+  if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
+  {
+    cupsdLogMessage(CUPSD_LOG_WARN,
+                    "CreateProfile failed: Incorrect reply type.");
+    goto out;
+  }
+
+  dbus_message_iter_get_basic(&args, &profile_path);
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "Created profile \"%s\".", profile_path);
+  cupsArrayAdd(profiles, strdup(profile_path));
+
+out:
+
+  if (message)
+    dbus_message_unref(message);
+
+  if (reply)
+    dbus_message_unref(reply);
+
+  if (idstr)
+    free(idstr);
+}
+
+
+/*
+ * 'colord_delete_device()' - Delete a device
+ */
+
+static void
+colord_delete_device(
+    const char *device_id)             /* I - Device ID string */
+{
+  DBusMessage  *message = NULL;        /* D-Bus request */
+  DBusMessage  *reply = NULL;          /* D-Bus reply */
+  DBusMessageIter args;                        /* D-Bus method arguments */
+  DBusError    error;                  /* D-Bus error */
+  char         *device_path;           /* Device object path */
+
+
+ /*
+  * Find the device...
+  */
+
+  if ((device_path = colord_find_device(device_id)) == NULL)
+    goto out;
+
+ /*
+  * Delete the device...
+  */
+
+  message = COLORD_DBUS_MSG(COLORD_DBUS_PATH, "DeleteDevice");
+
+  dbus_message_iter_init_append(message, &args);
+  dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_id);
+
+ /*
+  * Send the DeleteDevice request synchronously...
+  */
+
+  dbus_error_init(&error);
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling DeleteDevice(%s)", device_id);
+  reply = dbus_connection_send_with_reply_and_block(colord_con, message,
+                                                    COLORD_DBUS_TIMEOUT,
+                                                    &error);
+  if (!reply)
+  {
+    cupsdLogMessage(CUPSD_LOG_DEBUG, "DeleteDevice failed: %s:%s", error.name,
+                    error.message);
+    dbus_error_free(&error);
+    goto out;
+  }
+
+out:
+
+  if (device_path)
+    free(device_path);
+
+  if (message)
+    dbus_message_unref(message);
+
+  if (reply)
+    dbus_message_unref(reply);
+}
+
+
+/*
+ * 'colord_device_add_profile()' - Assign a profile to a device.
+ */
+
+static void
+colord_device_add_profile(
+    const char *device_path,           /* I - Device object path */
+    const char *profile_path,          /* I - Profile object path */
+    const char *relation)              /* I - Device relation, either
+                                              'soft' or 'hard' */
+{
+  DBusMessage  *message = NULL;        /* D-Bus request */
+  DBusMessage  *reply = NULL;          /* D-Bus reply */
+  DBusMessageIter args;                        /* D-Bus method arguments */
+  DBusError    error;                  /* D-Bus error */
+
+
+  message = COLORD_DBUS_MSG(device_path, "AddProfile");
+
+  dbus_message_iter_init_append(message, &args);
+  dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &relation);
+  dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &profile_path);
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling %s:AddProfile(%s) [%s]",
+                  device_path, profile_path, relation);
+
+ /*
+  * Send the AddProfile request synchronously...
+  */
+
+  dbus_error_init(&error);
+  reply = dbus_connection_send_with_reply_and_block(colord_con, message,
+                                                    COLORD_DBUS_TIMEOUT,
+                                                    &error);
+  if (!reply)
+  {
+    cupsdLogMessage(CUPSD_LOG_WARN, "AddProfile failed: %s:%s", error.name,
+                    error.message);
+    dbus_error_free(&error);
+    goto out;
+  }
+
+out:
+
+  if (message)
+    dbus_message_unref(message);
+
+  if (reply)
+    dbus_message_unref(reply);
+}
+
+
+/*
+ * 'colord_dict_add_strings()' - Add two strings to a dictionary.
+ */
+
+static void
+colord_dict_add_strings(
+    DBusMessageIter *dict,             /* I - Dictionary */
+    const char      *key,              /* I - Key string */
+    const char      *value)            /* I - Value string */
+{
+  DBusMessageIter      entry;          /* Entry to add */
+
+
+  dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry);
+  dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+  dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &value);
+  dbus_message_iter_close_container(dict, &entry);
+}
+
+
+/*
+ * 'colord_find_device()' - Finds a device
+ */
+
+static char *                          /* O - Device path or NULL */
+colord_find_device(
+    const char *device_id)             /* I - Device ID string */
+{
+  DBusMessage  *message = NULL;        /* D-Bus request */
+  DBusMessage  *reply = NULL;          /* D-Bus reply */
+  DBusMessageIter args;                        /* D-Bus method arguments */
+  DBusError    error;                  /* D-Bus error */
+  const char   *device_path_tmp;       /* Device object path */
+  char         *device_path = NULL;    /* Device object path */
+
+
+  message = COLORD_DBUS_MSG(COLORD_DBUS_PATH, "FindDeviceById");
+
+  dbus_message_iter_init_append(message, &args);
+  dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_id);
+
+ /*
+  * Send the FindDeviceById request synchronously...
+  */
+
+  dbus_error_init(&error);
+  cupsdLogMessage(CUPSD_LOG_DEBUG, "Calling FindDeviceById(%s)", device_id);
+  reply = dbus_connection_send_with_reply_and_block(colord_con, message,
+                                                    COLORD_DBUS_TIMEOUT,
+                                                    &error);
+  if (!reply)
+  {
+    cupsdLogMessage(CUPSD_LOG_DEBUG, "FindDeviceById failed: %s:%s",
+                   error.name, error.message);
+    dbus_error_free(&error);
+    goto out;
+  }
+
+ /*
+  * Get reply data...
+  */
+
+  dbus_message_iter_init(reply, &args);
+  if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
+  {
+    cupsdLogMessage(CUPSD_LOG_WARN,
+                    "FindDeviceById failed: Incorrect reply type.");
+    goto out;
+  }
+
+  dbus_message_iter_get_basic(&args, &device_path_tmp);
+  if (device_path_tmp)
+    device_path = strdup(device_path_tmp);
+
+out:
+
+  if (message)
+    dbus_message_unref(message);
+
+  if (reply)
+    dbus_message_unref(reply);
+
+  return (device_path);
+}
+
+
+/*
+ * 'colord_get_qualifier_format()' - Get the qualifier format.
+ *
+ * Note: Returns a value of "ColorSpace.MediaType.Resolution" by default.
+ */
+
+static void
+colord_get_qualifier_format(
+    ppd_file_t *ppd,                   /* I - PPD file data */
+    char       *format[3])             /* I - Format tuple */
+{
+  const char   *tmp;                   /* Temporary string */
+  ppd_attr_t   *attr;                  /* Profile attributes */
+
+
+ /*
+  * Get 1st section...
+  */
+
+  if ((attr = ppdFindAttr(ppd, "cupsICCQualifier1", NULL)) != NULL)
+    tmp = attr->value;
+  else if (ppdFindAttr(ppd, "DefaultColorModel", NULL))
+    tmp = "ColorModel";
+  else if (ppdFindAttr(ppd, "DefaultColorSpace", NULL))
+    tmp = "ColorSpace";
+  else
+    tmp = "";
+
+  format[0] = strdup(tmp);
+
+ /*
+  * Get 2nd section...
+  */
+
+  if ((attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL)
+    tmp = attr->value;
+  else
+    tmp = "MediaType";
+
+  format[1] = strdup(tmp);
+
+ /*
+  * Get 3rd section...
+  */
+
+  if ((attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL)
+    tmp = attr->value;
+  else
+    tmp = "Resolution";
+
+  format[2] = strdup(tmp);
+}
+
+
+/*
+ * 'colord_register_printer()' - Register profiles for a printer.
+ */
+
+static void
+colord_register_printer(
+    cupsd_printer_t *p)                        /* I - printer */
+{
+  char         ppdfile[1024],          /* PPD filename */
+               iccfile[1024];          /* ICC filename */
+  ppd_file_t   *ppd;                   /* PPD file */
+  cups_array_t *profiles;              /* Profile paths array */
+  ppd_attr_t   *attr;                  /* Profile attributes */
+  const char   *device_colorspace;     /* Device colorspace */
+  char         *format[3];             /* Qualifier format tuple */
+
+
+ /*
+  * Ensure we have a D-Bus connection...
+  */
+
+  if (!colord_con)
+    return;
+
+ /*
+  * Try opening the PPD file for this printer...
+  */
+
+  snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name);
+  if ((ppd = _ppdOpenFile(ppdfile, _PPD_LOCALIZATION_ICC_PROFILES)) == NULL)
+    return;
+
+ /*
+  * Find out the qualifier format
+  */
+
+  colord_get_qualifier_format(ppd, format);
+
+ /*
+  * See if we have any embedded profiles...
+  */
+
+  profiles = cupsArrayNew3(NULL, NULL, NULL, 0, (cups_acopy_func_t)strdup,
+                          (cups_afree_func_t)free);
+  for (attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
+       attr;
+       attr = ppdFindNextAttr(ppd, "cupsICCProfile", NULL))
+    if (attr->spec[0] && attr->value && attr->value[0])
+    {
+      if (attr->value[0] != '/')
+        snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir,
+                 attr->value);
+      else
+        strlcpy(iccfile, attr->value, sizeof(iccfile));
+
+      if (_cupsFileCheck(iccfile, _CUPS_FILE_CHECK_FILE, !RunUser,
+                        cupsdLogFCMessage, p))
+       continue;
+
+      colord_create_profile(profiles, p->name, attr->spec, COLORD_SPACE_UNKNOWN,
+                           format, iccfile, COLORD_SCOPE_TEMP);
+    }
+
+ /*
+  * Add the grayscale profile first.  We always have a grayscale profile.
+  */
+
+  colord_create_profile(profiles, p->name, "Gray..", COLORD_SPACE_GRAY,
+                        format, NULL, COLORD_SCOPE_TEMP);
+
+ /*
+  * Then add the RGB/CMYK/DeviceN color profile...
+  */
+
+  device_colorspace = "unknown";
+  switch (ppd->colorspace)
+  {
+    case PPD_CS_RGB :
+    case PPD_CS_CMY :
+        device_colorspace = COLORD_SPACE_RGB;
+        colord_create_profile(profiles, p->name, "RGB..", COLORD_SPACE_RGB,
+                             format, NULL, COLORD_SCOPE_TEMP);
+        break;
+
+    case PPD_CS_RGBK :
+    case PPD_CS_CMYK :
+        device_colorspace = COLORD_SPACE_CMYK;
+        colord_create_profile(profiles, p->name, "CMYK..", COLORD_SPACE_CMYK,
+                              format, NULL, COLORD_SCOPE_TEMP);
+        break;
+
+    case PPD_CS_GRAY :
+        device_colorspace = COLORD_SPACE_GRAY;
+        break;
+
+    case PPD_CS_N :
+        colord_create_profile(profiles, p->name, "DeviceN..",
+                              COLORD_SPACE_UNKNOWN, format, NULL,
+                             COLORD_SCOPE_TEMP);
+        break;
+  }
+
+ /*
+  * Register the device with colord.
+  */
+
+  cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for \"%s\".",
+                  p->name);
+  colord_create_device(p, ppd, profiles, device_colorspace, format,
+                      COLORD_RELATION_SOFT, COLORD_SCOPE_TEMP);
+
+ /*
+  * Free any memory we used...
+  */
+
+  cupsArrayDelete(profiles);
+
+  free(format[0]);
+  free(format[1]);
+  free(format[2]);
+
+  ppdClose(ppd);
+}
+
+
+/*
+ * 'colord_unregister_printer()' - Unregister profiles for a printer.
+ */
+
+static void
+colord_unregister_printer(
+    cupsd_printer_t *p)                        /* I - printer */
+{
+  char device_id[1024];                /* Device ID as understood by colord */
+
+
+ /*
+  * Ensure we have a D-Bus connection...
+  */
+
+  if (!colord_con)
+    return;
+
+ /*
+  * Just delete the device itself, and leave the profiles registered
+  */
+
+  snprintf(device_id, sizeof(device_id), "cups-%s", p->name);
+  colord_delete_device(device_id);
+}
+#endif /* __APPLE__ */
+
+
+/*
+ * End of "$Id$".
+ */
diff --git a/scheduler/colorman.h b/scheduler/colorman.h
new file mode 100644 (file)
index 0000000..e912a92
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * "$Id$"
+ *
+ *   Color management definitions for the CUPS scheduler.
+ *
+ *   Copyright 2007-2012 by Apple Inc.
+ *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
+ *
+ *   These coded instructions, statements, and computer programs are the
+ *   property of Apple Inc. and are protected by Federal copyright
+ *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ *   which should have been included with this file.  If this file is
+ *   file is missing or damaged, see the license at "http://www.cups.org/".
+ */
+
+/*
+ * Prototypes...
+ */
+
+extern void    cupsdRegisterColor(cupsd_printer_t *p);
+extern void    cupsdStartColor(void);
+extern void    cupsdStopColor(void);
+extern void    cupsdUnregisterColor(cupsd_printer_t *p);
+
+
+/*
+ * End of "$Id$".
+ */
index 4d392452b3d9c48b5e89f4fe2504afd9ee4e2375..a7ec4151c91dc774bb652c64098bf243b74cb373 100644 (file)
@@ -169,6 +169,7 @@ static const cupsd_var_t    variables[] =
   { "ServerRoot",              &ServerRoot,            CUPSD_VARTYPE_PATHNAME },
   { "SMBConfigFile",           &SMBConfigFile,         CUPSD_VARTYPE_STRING },
   { "StateDir",                        &StateDir,              CUPSD_VARTYPE_STRING },
+  { "StrictConformance",       &StrictConformance,     CUPSD_VARTYPE_BOOLEAN },
 #ifdef HAVE_AUTHORIZATION_H
   { "SystemGroupAuthKey",      &SystemGroupAuthKey,    CUPSD_VARTYPE_STRING },
 #endif /* HAVE_AUTHORIZATION_H */
@@ -722,10 +723,11 @@ cupsdReadConfiguration(void)
   MaxLogSize               = 1024 * 1024;
   MaxRequestSize           = 0;
   MultipleOperationTimeout = DEFAULT_TIMEOUT;
+  NumSystemGroups          = 0;
   ReloadTimeout                   = DEFAULT_KEEPALIVE;
   RootCertDuration         = 300;
+  StrictConformance        = FALSE;
   Timeout                  = DEFAULT_TIMEOUT;
-  NumSystemGroups          = 0;
   WebInterface             = CUPS_DEFAULT_WEBIF;
 
   BrowseLocalProtocols     = parse_protocols(CUPS_DEFAULT_BROWSE_LOCAL_PROTOCOLS);
index 5edfde429daf521de286ec536717f567a764fd69..741855ae3fac959bb2a38d62f3c2d021ebbb9afa 100644 (file)
@@ -169,6 +169,8 @@ VAR int                     ClassifyOverride        VALUE(0),
                                        /* Amount of automatic debug history */
                        FatalErrors             VALUE(CUPSD_FATAL_CONFIG),
                                        /* Which errors are fatal? */
+                       StrictConformance       VALUE(FALSE),
+                                       /* Require strict IPP conformance? */
                        LogFilePerm             VALUE(0644);
                                        /* Permissions for log files */
 VAR cupsd_loglevel_t   LogLevel                VALUE(CUPSD_LOG_WARN);
index 3c23d6247269cdd07a2dddfc759c637d033e91f4..1a270b3729d59ea003f1feaccd6b47d96a773b1f 100644 (file)
@@ -671,7 +671,7 @@ cat_tar(const char *name,           /* I - PPD name */
 
       for (total = 0; total < curinfo.st_size; total += bytes)
       {
-        if ((bytes = (curinfo.st_size - total)) > sizeof(buffer))
+        if ((size_t)(bytes = (curinfo.st_size - total)) > sizeof(buffer))
           bytes = sizeof(buffer);
 
         if ((bytes = cupsFileRead(fp, buffer, bytes)) < 0)
@@ -1997,7 +1997,7 @@ load_ppd(const char  *filename,           /* I - Real filename */
   cups_array_t *products,              /* Product array */
                *psversions,            /* PSVersion array */
                *cups_languages;        /* cupsLanguages array */
-  int          new_ppd = !ppd;         /* Is this a new PPD? */
+  int          new_ppd;                /* Is this a new PPD? */
   struct                               /* LanguageVersion translation table */
   {
     const char *version,               /* LanguageVersion string */
index aaf9b13c01d3e40f32946c374374174cc8a9ce0e..b15336b518fa56b59e7984a54139d4d478e9af4d 100644 (file)
@@ -3,7 +3,7 @@
  *
  *   Main header file for the CUPS scheduler.
  *
- *   Copyright 2007-2011 by Apple Inc.
+ *   Copyright 2007-2012 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
@@ -116,6 +116,7 @@ extern const char *cups_hstrerror(int);
 #include "printers.h"
 #include "classes.h"
 #include "job.h"
+#include "colorman.h"
 #include "conf.h"
 #include "banners.h"
 #include "dirsvc.h"
index e57b3f13d8699474496dc749671511b3b95c0b25..af90998099bad2a40b9f4246f470ffabb900f107 100644 (file)
 
 #if defined(HAVE_DNSSD) && defined(__APPLE__)
 #  include <nameser.h>
-#  ifdef HAVE_COREFOUNDATION
-#    include <CoreFoundation/CoreFoundation.h>
-#  endif /* HAVE_COREFOUNDATION */
-#  ifdef HAVE_SYSTEMCONFIGURATION
-#    include <SystemConfiguration/SystemConfiguration.h>
-#  endif /* HAVE_SYSTEMCONFIGURATION */
+#  include <CoreFoundation/CoreFoundation.h>
+#  include <SystemConfiguration/SystemConfiguration.h>
 #endif /* HAVE_DNSSD && __APPLE__ */
 
 
@@ -77,10 +73,10 @@ static void         update_smb(int onoff);
 
 
 #if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
-#  ifdef HAVE_COREFOUNDATION
+#  ifdef __APPLE__
 static void            dnssdAddAlias(const void *key, const void *value,
                                      void *context);
-#  endif /* HAVE_COREFOUNDATION */
+#  endif /* __APPLE__ */
 static cupsd_txt_t     dnssdBuildTxtRecord(cupsd_printer_t *p, int for_lpd);
 static void            dnssdDeregisterInstance(cupsd_srv_t *srv);
 static void            dnssdDeregisterPrinter(cupsd_printer_t *p,
@@ -140,8 +136,10 @@ cupsdDeregisterPrinter(
   * Announce the deletion...
   */
 
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
   if (removeit && (BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDMaster)
     dnssdDeregisterPrinter(p, 1);
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
 }
 
 
@@ -160,8 +158,10 @@ cupsdRegisterPrinter(cupsd_printer_t *p)/* I - Printer */
       (p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_SCANNER)))
     return;
 
+#if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
   if ((BrowseLocalProtocols & BROWSE_DNSSD) && DNSSDMaster)
     dnssdRegisterPrinter(p);
+#endif /* HAVE_DNSSD || HAVE_AVAHI */
 }
 
 
@@ -342,13 +342,13 @@ void
 cupsdUpdateDNSSDName(void)
 {
   char         webif[1024];            /* Web interface share name */
-#  ifdef HAVE_SYSTEMCONFIGURATION
+#  ifdef __APPLE__
   SCDynamicStoreRef sc;                        /* Context for dynamic store */
   CFDictionaryRef btmm;                        /* Back-to-My-Mac domains */
   CFStringEncoding nameEncoding;       /* Encoding of computer name */
   CFStringRef  nameRef;                /* Host name CFString */
   char         nameBuffer[1024];       /* C-string buffer */
-#  endif /* HAVE_SYSTEMCONFIGURATION */
+#  endif /* __APPLE__ */
 
 
  /*
@@ -363,7 +363,7 @@ cupsdUpdateDNSSDName(void)
   * Get the computer name as a c-string...
   */
 
-#  ifdef HAVE_SYSTEMCONFIGURATION
+#  ifdef __APPLE__
   sc = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("cupsd"), NULL, NULL);
 
   if (sc)
@@ -454,7 +454,7 @@ cupsdUpdateDNSSDName(void)
     CFRelease(sc);
   }
   else
-#  endif /* HAVE_SYSTEMCONFIGURATION */
+#  endif /* __APPLE__ */
 #  ifdef HAVE_AVAHI
   {
     cupsdSetString(&DNSSDComputerName, avahi_client_get_host_name(DNSSDClient));
@@ -486,7 +486,7 @@ cupsdUpdateDNSSDName(void)
 }
 
 
-#  ifdef HAVE_COREFOUNDATION
+#  ifdef __APPLE__
 /*
  * 'dnssdAddAlias()' - Add a DNS-SD alias name.
  */
@@ -524,7 +524,7 @@ dnssdAddAlias(const void *key,              /* I - Key */
     cupsdLogMessage(CUPSD_LOG_ERROR,
                     "Bad Back to My Mac domain in dynamic store!");
 }
-#  endif /* HAVE_COREFOUNDATION */
+#  endif /* __APPLE__ */
 
 
 /*
index ec12d155f021719ca27cbf6b6bb73857a225c850..5fbe52c559d9f7c72309cecdf15fd236d1d17cf9 100644 (file)
@@ -62,7 +62,7 @@ cupsdInitEnv(void)
 
 #if defined(__APPLE__)
  /*
-  * Add special voodoo magic for MacOS X - this allows MacOS X 
+  * Add special voodoo magic for MacOS X - this allows MacOS X
   * programs to access their bundle resources properly...
   *
   * This string is replaced in cupsdStartProcess()...
@@ -227,6 +227,8 @@ cupsdUpdateEnv(void)
   set_if_undefined("TZ", NULL);
   set_if_undefined("USER", "root");
   set_if_undefined("VG_ARGS", NULL);
+
+  cupsdSetEnvf("CUPS_MAX_MESSAGE", "%d", CUPSD_SB_BUFFER_SIZE - 1);
 }
 
 
index ce0ccc9f0701f45e46038c5bbc358591a5813646..fb0e47dc1e86af2661ca6f092bb40faef4f26a33 100644 (file)
  *                                 based upon the printer state...
  *   add_queued_job_count()      - Add the "queued-job-count" attribute for the
  *                                 specified printer or class.
- *   apple_init_profile()        - Initialize a color profile.
- *   apple_register_profiles()   - Register color profiles for a printer.
- *   apple_unregister_profiles() - Remove color profiles for the specified
- *                                 printer.
  *   apply_printer_defaults()    - Apply printer default options to a job.
  *   authenticate_job()          - Set job authentication info.
  *   cancel_all_jobs()           - Cancel all or selected print jobs.
 #include <cups/ppd-private.h>
 
 #ifdef __APPLE__
-#  include <ApplicationServices/ApplicationServices.h>
+/*#  include <ApplicationServices/ApplicationServices.h>
 extern CFUUIDRef ColorSyncCreateUUIDFromUInt32(unsigned id);
-#  include <CoreFoundation/CoreFoundation.h>
+#  include <CoreFoundation/CoreFoundation.h>*/
 #  ifdef HAVE_MEMBERSHIP_H
 #    include <membership.h>
 #  endif /* HAVE_MEMBERSHIP_H */
@@ -143,14 +139,6 @@ static void        add_printer(cupsd_client_t *con, ipp_attribute_t *uri);
 static void    add_printer_state_reasons(cupsd_client_t *con,
                                          cupsd_printer_t *p);
 static void    add_queued_job_count(cupsd_client_t *con, cupsd_printer_t *p);
-#ifdef __APPLE__
-static void    apple_init_profile(ppd_file_t *ppd, cups_array_t *languages,
-                                   CFMutableDictionaryRef profile,
-                                  unsigned id, const char *name,
-                                  const char *text, const char *iccfile);
-static void    apple_register_profiles(cupsd_printer_t *p);
-static void    apple_unregister_profiles(cupsd_printer_t *p);
-#endif /* __APPLE__ */
 static void    apply_printer_defaults(cupsd_printer_t *printer,
                                       cupsd_job_t *job);
 static void    authenticate_job(cupsd_client_t *con, ipp_attribute_t *uri);
@@ -2738,17 +2726,11 @@ add_printer(cupsd_client_t  *con,       /* I - Client connection */
 
     cupsdSetPrinterReasons(printer, "none");
 
-#ifdef __APPLE__
    /*
     * (Re)register color profiles...
     */
 
-    if (!RunUser)
-    {
-      apple_unregister_profiles(printer);
-      apple_register_profiles(printer);
-    }
-#endif /* __APPLE__ */
+    cupsdRegisterColor(printer);
   }
 
  /*
@@ -2882,711 +2864,6 @@ add_queued_job_count(
 }
 
 
-#ifdef __APPLE__
-/*
- * 'apple_init_profile()' - Initialize a color profile.
- */
-
-static void
-apple_init_profile(
-    ppd_file_t             *ppd,       /* I - PPD file */
-    cups_array_t          *languages,  /* I - Languages in the PPD file */
-    CFMutableDictionaryRef profile,    /* I - Profile dictionary */
-    unsigned               id,         /* I - Profile ID */
-    const char             *name,      /* I - Profile name */
-    const char             *text,      /* I - Profile UI text */
-    const char             *iccfile)   /* I - ICC filename */
-{
-  CFURLRef             url;            /* URL for profile filename */
-  CFMutableDictionaryRef dict;         /* Dictionary for name */
-  char                 *language;      /* Current language */
-  ppd_attr_t           *attr;          /* Profile attribute */
-  CFStringRef          cflang,         /* Language string */
-                       cftext;         /* Localized text */
-
-
-  (void)id;
-
- /*
-  * Build the profile name dictionary...
-  */
-
-  dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
-                                  &kCFTypeDictionaryKeyCallBacks,
-                                  &kCFTypeDictionaryValueCallBacks);
-  if (!dict)
-  {
-    cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to initialize profile \"%s\".",
-                    iccfile);
-    return;
-  }
-
-  cftext = CFStringCreateWithCString(kCFAllocatorDefault, text,
-                                    kCFStringEncodingUTF8);
-
-  if (cftext)
-  {
-    CFDictionarySetValue(dict, CFSTR("en_US"), cftext);
-    CFRelease(cftext);
-  }
-
-  if (languages)
-  {
-   /*
-    * Find localized names for the color profiles...
-    */
-
-    cupsArraySave(ppd->sorted_attrs);
-
-    for (language = (char *)cupsArrayFirst(languages);
-        language;
-        language = (char *)cupsArrayNext(languages))
-    {
-      if (iccfile)
-      {
-        if ((attr = _ppdLocalizedAttr(ppd, "cupsICCProfile", name,
-                                     language)) == NULL)
-         attr = _ppdLocalizedAttr(ppd, "APTiogaProfile", name, language);
-      }
-      else
-        attr = _ppdLocalizedAttr(ppd, "ColorModel", name, language);
-
-      if (attr && attr->text[0])
-      {
-       cflang = CFStringCreateWithCString(kCFAllocatorDefault, language,
-                                          kCFStringEncodingUTF8);
-       cftext = CFStringCreateWithCString(kCFAllocatorDefault, attr->text,
-                                          kCFStringEncodingUTF8);
-
-        if (cflang && cftext)
-         CFDictionarySetValue(dict, cflang, cftext);
-
-        if (cflang)
-         CFRelease(cflang);
-
-        if (cftext)
-         CFRelease(cftext);
-      }
-    }
-
-    cupsArrayRestore(ppd->sorted_attrs);
-  }
-
- /*
-  * Fill in the profile data...
-  */
-
- if (iccfile)
- {
-    url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
-                                                 (const UInt8 *)iccfile,
-                                                  strlen(iccfile), false);
-
-    if (url)
-    {
-      CFDictionarySetValue(profile, kColorSyncDeviceProfileURL, url);
-      CFRelease(url);
-    }
-  }
-
-  CFDictionarySetValue(profile, kColorSyncDeviceModeDescriptions, dict);
-  CFRelease(dict);
-}
-
-
-/*
- * 'apple_register_profiles()' - Register color profiles for a printer.
- */
-
-static void
-apple_register_profiles(
-    cupsd_printer_t *p)                        /* I - Printer */
-{
-  int                  i;              /* Looping var */
-  char                 ppdfile[1024],  /* PPD filename */
-                       iccfile[1024],  /* ICC filename */
-                       selector[PPD_MAX_NAME];
-                                       /* Profile selection string */
-  ppd_file_t           *ppd;           /* PPD file */
-  ppd_attr_t           *attr,          /* Profile attributes */
-                       *profileid_attr,/* cupsProfileID attribute */
-                       *q1_attr,       /* ColorModel (or other) qualifier */
-                       *q2_attr,       /* MediaType (or other) qualifier */
-                       *q3_attr;       /* Resolution (or other) qualifier */
-  char                 q_keyword[PPD_MAX_NAME];
-                                       /* Qualifier keyword */
-  const char           *q1_choice,     /* ColorModel (or other) choice */
-                       *q2_choice,     /* MediaType (or other) choice */
-                       *q3_choice;     /* Resolution (or other) choice */
-  const char           *profile_key;   /* Profile keyword */
-  ppd_option_t         *cm_option;     /* Color model option */
-  ppd_choice_t         *cm_choice;     /* Color model choice */
-  int                  num_profiles;   /* Number of profiles */
-  OSStatus             error = 0;      /* Last error */
-  unsigned             device_id,      /* Printer device ID */
-                       profile_id = 0, /* Profile ID */
-                       default_profile_id = 0;
-                                       /* Default profile ID */
-  CFMutableDictionaryRef device_name;  /* Printer device name dictionary */
-  CFStringRef          printer_name;   /* Printer name string */
-  cups_array_t         *languages;     /* Languages array */
-  CFMutableDictionaryRef profiles,     /* Dictionary of profiles */
-                       profile;        /* Current profile info dictionary */
-  CFStringRef          dict_key;       /* Key in factory profile dictionary */
-
-
- /*
-  * Make sure ColorSync is available...
-  */
-
-  if (ColorSyncRegisterDevice == NULL)
-    return;
-
- /*
-  * Try opening the PPD file for this printer...
-  */
-
-  snprintf(ppdfile, sizeof(ppdfile), "%s/ppd/%s.ppd", ServerRoot, p->name);
-  if ((ppd = _ppdOpenFile(ppdfile, _PPD_LOCALIZATION_ICC_PROFILES)) == NULL)
-    return;
-
- /*
-  * See if we have any profiles...
-  */
-
-  if ((attr = ppdFindAttr(ppd, "APTiogaProfile", NULL)) != NULL)
-    profile_key = "APTiogaProfile";
-  else
-  {
-    attr = ppdFindAttr(ppd, "cupsICCProfile", NULL);
-    profile_key = "cupsICCProfile";
-  }
-
-  for (num_profiles = 0; attr; attr = ppdFindNextAttr(ppd, profile_key, NULL))
-    if (attr->spec[0] && attr->value && attr->value[0])
-    {
-      if (attr->value[0] != '/')
-       snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir,
-                attr->value);
-      else
-       strlcpy(iccfile, attr->value, sizeof(iccfile));
-
-      if (access(iccfile, 0))
-      {
-        cupsdLogMessage(CUPSD_LOG_ERROR,
-                        "%s: ICC Profile \"%s\" does not exist.", p->name,
-                        iccfile);
-        cupsdSetPrinterReasons(p, "+cups-missing-filter-warning");
-       continue;
-      }
-
-      num_profiles ++;
-    }
-
- /*
-  * Create a dictionary for the factory profiles...
-  */
-
-  profiles = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
-                                      &kCFTypeDictionaryKeyCallBacks,
-                                      &kCFTypeDictionaryValueCallBacks);
-  if (!profiles)
-  {
-    cupsdLogMessage(CUPSD_LOG_ERROR,
-                   "Unable to allocate memory for factory profiles.");
-    ppdClose(ppd);
-    return;
-  }
-
- /*
-  * If we have profiles, add them...
-  */
-
-  if (num_profiles > 0)
-  {
-    if (profile_key[0] == 'A')
-    {
-     /*
-      * For Tioga PPDs, get the default profile using the DefaultAPTiogaProfile
-      * attribute...
-      */
-
-      if ((attr = ppdFindAttr(ppd, "DefaultAPTiogaProfile", NULL)) != NULL &&
-         attr->value)
-        default_profile_id = atoi(attr->value);
-
-      q1_choice = q2_choice = q3_choice = NULL;
-    }
-    else
-    {
-     /*
-      * For CUPS PPDs, figure out the default profile selector values...
-      */
-
-      if ((attr = ppdFindAttr(ppd, "cupsICCQualifier1", NULL)) != NULL &&
-         attr->value && attr->value[0])
-      {
-       snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
-       q1_attr = ppdFindAttr(ppd, q_keyword, NULL);
-      }
-      else if ((q1_attr = ppdFindAttr(ppd, "DefaultColorModel", NULL)) == NULL)
-       q1_attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL);
-
-      if (q1_attr && q1_attr->value && q1_attr->value[0])
-       q1_choice = q1_attr->value;
-      else
-       q1_choice = "";
-
-      if ((attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL &&
-         attr->value && attr->value[0])
-      {
-       snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
-       q2_attr = ppdFindAttr(ppd, q_keyword, NULL);
-      }
-      else
-       q2_attr = ppdFindAttr(ppd, "DefaultMediaType", NULL);
-
-      if (q2_attr && q2_attr->value && q2_attr->value[0])
-       q2_choice = q2_attr->value;
-      else
-       q2_choice = NULL;
-
-      if ((attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL &&
-         attr->value && attr->value[0])
-      {
-       snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
-       q3_attr = ppdFindAttr(ppd, q_keyword, NULL);
-      }
-      else
-       q3_attr = ppdFindAttr(ppd, "DefaultResolution", NULL);
-
-      if (q3_attr && q3_attr->value && q3_attr->value[0])
-       q3_choice = q3_attr->value;
-      else
-       q3_choice = NULL;
-    }
-
-   /*
-    * Loop through the profiles listed in the PPD...
-    */
-
-    languages = _ppdGetLanguages(ppd);
-
-    for (attr = ppdFindAttr(ppd, profile_key, NULL);
-        attr;
-        attr = ppdFindNextAttr(ppd, profile_key, NULL))
-      if (attr->spec[0] && attr->value && attr->value[0])
-      {
-       /*
-        * Add this profile...
-       */
-
-        if (attr->value[0] != '/')
-         snprintf(iccfile, sizeof(iccfile), "%s/profiles/%s", DataDir,
-                  attr->value);
-        else
-         strlcpy(iccfile, attr->value, sizeof(iccfile));
-
-        if (_cupsFileCheck(iccfile, _CUPS_FILE_CHECK_FILE, !RunUser,
-                          cupsdLogFCMessage, p))
-         continue;
-
-        if (profile_key[0] == 'c')
-       {
-         cupsArraySave(ppd->sorted_attrs);
-
-         if ((profileid_attr = ppdFindAttr(ppd, "cupsProfileID",
-                                           attr->spec)) != NULL &&
-             profileid_attr->value && isdigit(profileid_attr->value[0] & 255))
-           profile_id = (unsigned)strtoul(profileid_attr->value, NULL, 10);
-         else
-           profile_id = _ppdHashName(attr->spec);
-
-         cupsArrayRestore(ppd->sorted_attrs);
-        }
-       else
-         profile_id = atoi(attr->spec);
-
-       profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
-                                           &kCFTypeDictionaryKeyCallBacks,
-                                           &kCFTypeDictionaryValueCallBacks);
-       if (!profile)
-       {
-         cupsdLogMessage(CUPSD_LOG_ERROR,
-                         "Unable to allocate memory for color profile.");
-         CFRelease(profiles);
-         ppdClose(ppd);
-         return;
-       }
-
-       apple_init_profile(ppd, languages, profile, profile_id, attr->spec,
-                          attr->text[0] ? attr->text : attr->spec, iccfile);
-
-       dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
-                                           CFSTR("%u"), profile_id);
-       if (dict_key)
-       {
-         CFDictionarySetValue(profiles, dict_key, profile);
-         CFRelease(dict_key);
-       }
-
-       CFRelease(profile);
-
-       /*
-        * See if this is the default profile...
-       */
-
-        if (!default_profile_id && q1_choice && q2_choice && q3_choice)
-       {
-         snprintf(selector, sizeof(selector), "%s.%s.%s", q1_choice, q2_choice,
-                  q3_choice);
-         if (!strcmp(selector, attr->spec))
-           default_profile_id = profile_id;
-       }
-
-        if (!default_profile_id && q1_choice && q2_choice)
-       {
-         snprintf(selector, sizeof(selector), "%s.%s.", q1_choice, q2_choice);
-         if (!strcmp(selector, attr->spec))
-           default_profile_id = profile_id;
-       }
-
-        if (!default_profile_id && q1_choice && q3_choice)
-       {
-         snprintf(selector, sizeof(selector), "%s..%s", q1_choice, q3_choice);
-         if (!strcmp(selector, attr->spec))
-           default_profile_id = profile_id;
-       }
-
-        if (!default_profile_id && q1_choice)
-       {
-         snprintf(selector, sizeof(selector), "%s..", q1_choice);
-         if (!strcmp(selector, attr->spec))
-           default_profile_id = profile_id;
-       }
-
-        if (!default_profile_id && q2_choice && q3_choice)
-       {
-         snprintf(selector, sizeof(selector), ".%s.%s", q2_choice, q3_choice);
-         if (!strcmp(selector, attr->spec))
-           default_profile_id = profile_id;
-       }
-
-        if (!default_profile_id && q2_choice)
-       {
-         snprintf(selector, sizeof(selector), ".%s.", q2_choice);
-         if (!strcmp(selector, attr->spec))
-           default_profile_id = profile_id;
-       }
-
-        if (!default_profile_id && q3_choice)
-       {
-         snprintf(selector, sizeof(selector), "..%s", q3_choice);
-         if (!strcmp(selector, attr->spec))
-           default_profile_id = profile_id;
-       }
-      }
-
-    _ppdFreeLanguages(languages);
-  }
-  else if ((cm_option = ppdFindOption(ppd, "ColorModel")) != NULL)
-  {
-   /*
-    * Extract profiles from ColorModel option...
-    */
-
-    const char *profile_name;          /* Name of generic profile */
-
-
-    num_profiles = cm_option->num_choices;
-
-    for (i = cm_option->num_choices, cm_choice = cm_option->choices;
-         i > 0;
-        i --, cm_choice ++)
-    {
-      if (!strcmp(cm_choice->choice, "Gray") ||
-          !strcmp(cm_choice->choice, "Black"))
-        profile_name = "Gray";
-      else if (!strcmp(cm_choice->choice, "RGB") ||
-               !strcmp(cm_choice->choice, "CMY"))
-        profile_name = "RGB";
-      else if (!strcmp(cm_choice->choice, "CMYK") ||
-               !strcmp(cm_choice->choice, "KCMY"))
-        profile_name = "CMYK";
-      else
-        profile_name = "DeviceN";
-
-      snprintf(selector, sizeof(selector), "%s..", profile_name);
-      profile_id = _ppdHashName(selector);
-
-      profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
-                                         &kCFTypeDictionaryKeyCallBacks,
-                                         &kCFTypeDictionaryValueCallBacks);
-      if (!profile)
-      {
-       cupsdLogMessage(CUPSD_LOG_ERROR,
-                       "Unable to allocate memory for color profile.");
-       CFRelease(profiles);
-       ppdClose(ppd);
-       return;
-      }
-
-      apple_init_profile(ppd, NULL, profile, profile_id, cm_choice->choice,
-                         cm_choice->text, NULL);
-
-      dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
-                                          CFSTR("%u"), profile_id);
-      if (dict_key)
-      {
-       CFDictionarySetValue(profiles, dict_key, profile);
-       CFRelease(dict_key);
-      }
-
-      CFRelease(profile);
-
-      if (cm_choice->marked)
-        default_profile_id = profile_id;
-    }
-  }
-  else
-  {
-   /*
-    * Use the default colorspace...
-    */
-
-    attr = ppdFindAttr(ppd, "DefaultColorSpace", NULL);
-
-    num_profiles = (attr && ppd->colorspace == PPD_CS_GRAY) ? 1 : 2;
-
-   /*
-    * Add the grayscale profile first.  We always have a grayscale profile.
-    */
-
-    profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
-                                       &kCFTypeDictionaryKeyCallBacks,
-                                       &kCFTypeDictionaryValueCallBacks);
-
-    if (!profile)
-    {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "Unable to allocate memory for color profile.");
-      CFRelease(profiles);
-      ppdClose(ppd);
-      return;
-    }
-
-    profile_id = _ppdHashName("Gray..");
-    apple_init_profile(ppd, NULL, profile, profile_id, "Gray", "Gray", NULL);
-
-    dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"),
-                                        profile_id);
-    if (dict_key)
-    {
-      CFDictionarySetValue(profiles, dict_key, profile);
-      CFRelease(dict_key);
-    }
-
-    CFRelease(profile);
-
-   /*
-    * Then add the RGB/CMYK/DeviceN color profile...
-    */
-
-    profile = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
-                                       &kCFTypeDictionaryKeyCallBacks,
-                                       &kCFTypeDictionaryValueCallBacks);
-
-    if (!profile)
-    {
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                      "Unable to allocate memory for color profile.");
-      CFRelease(profiles);
-      ppdClose(ppd);
-      return;
-    }
-
-    switch (ppd->colorspace)
-    {
-      default :
-      case PPD_CS_RGB :
-      case PPD_CS_CMY :
-          profile_id = _ppdHashName("RGB..");
-          apple_init_profile(ppd, NULL, profile, profile_id, "RGB", "RGB",
-                            NULL);
-          break;
-
-      case PPD_CS_RGBK :
-      case PPD_CS_CMYK :
-          profile_id = _ppdHashName("CMYK..");
-          apple_init_profile(ppd, NULL, profile, profile_id, "CMYK", "CMYK",
-                            NULL);
-          break;
-
-      case PPD_CS_GRAY :
-          if (attr)
-            break;
-
-      case PPD_CS_N :
-          profile_id = _ppdHashName("DeviceN..");
-          apple_init_profile(ppd, NULL, profile, profile_id, "DeviceN",
-                            "DeviceN", NULL);
-          break;
-    }
-
-    if (CFDictionaryGetCount(profile) > 0)
-    {
-      dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
-                                          CFSTR("%u"), profile_id);
-      if (dict_key)
-      {
-        CFDictionarySetValue(profiles, dict_key, profile);
-        CFRelease(dict_key);
-      }
-    }
-
-    CFRelease(profile);
-  }
-
-  if (num_profiles > 0)
-  {
-   /*
-    * Make sure we have a default profile ID...
-    */
-
-    if (!default_profile_id)
-      default_profile_id = profile_id; /* Last profile */
-
-    dict_key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"),
-                                        default_profile_id);
-    if (dict_key)
-    {
-      CFDictionarySetValue(profiles, kColorSyncDeviceDefaultProfileID,
-                           dict_key);
-      CFRelease(dict_key);
-    }
-
-   /*
-    * Get the device ID hash and pathelogical name dictionary.
-    */
-
-    cupsdLogMessage(CUPSD_LOG_INFO, "Registering ICC color profiles for \"%s\"",
-                   p->name);
-
-    device_id    = _ppdHashName(p->name);
-    device_name  = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
-                                            &kCFTypeDictionaryKeyCallBacks,
-                                            &kCFTypeDictionaryValueCallBacks);
-    printer_name = CFStringCreateWithCString(kCFAllocatorDefault,
-                                             p->name, kCFStringEncodingUTF8);
-
-    if (device_name && printer_name)
-    {
-     /*
-      * Register the device with ColorSync...
-      */
-
-      CFTypeRef                deviceDictKeys[] =
-      {                                        /* Device keys */
-        kColorSyncDeviceDescriptions,
-       kColorSyncFactoryProfiles,
-       kColorSyncDeviceUserScope,
-       kColorSyncDeviceHostScope
-      };
-      CFTypeRef        deviceDictVals[] =
-      {                                        /* Device values */
-        device_name,
-       profiles,
-       kCFPreferencesAnyUser,
-       kCFPreferencesCurrentHost
-      };
-      CFDictionaryRef  deviceDict;     /* Device dictionary */
-      CFUUIDRef                deviceUUID;     /* Device UUID */
-
-      CFDictionarySetValue(device_name, CFSTR("en_US"), printer_name);
-
-      deviceDict = CFDictionaryCreate(kCFAllocatorDefault,
-                                     (const void **)deviceDictKeys,
-                                     (const void **)deviceDictVals,
-                                     sizeof(deviceDictKeys) /
-                                         sizeof(deviceDictKeys[0]),
-                                     &kCFTypeDictionaryKeyCallBacks,
-                                     &kCFTypeDictionaryValueCallBacks);
-      deviceUUID = ColorSyncCreateUUIDFromUInt32(device_id);
-
-      if (!deviceDict || !deviceUUID ||
-         !ColorSyncRegisterDevice(kColorSyncPrinterDeviceClass, deviceUUID,
-                                  deviceDict))
-       error = 1001;
-
-      if (deviceUUID)
-        CFRelease(deviceUUID);
-
-      if (deviceDict)
-        CFRelease(deviceDict);
-    }
-    else
-      error = 1000;
-
-   /*
-    * Clean up...
-    */
-
-    if (error != noErr)
-      cupsdLogMessage(CUPSD_LOG_ERROR,
-                     "Unable to register ICC color profiles for \"%s\": %d",
-                     p->name, (int)error);
-
-    if (printer_name)
-      CFRelease(printer_name);
-
-    if (device_name)
-      CFRelease(device_name);
-  }
-
- /*
-  * Free any memory we used...
-  */
-
-  CFRelease(profiles);
-
-  ppdClose(ppd);
-}
-
-
-/*
- * 'apple_unregister_profiles()' - Remove color profiles for the specified
- *                                 printer.
- */
-
-static void
-apple_unregister_profiles(
-    cupsd_printer_t *p)                        /* I - Printer */
-{
- /*
-  * Make sure ColorSync is available...
-  */
-
-  if (ColorSyncUnregisterDevice != NULL)
-  {
-   /*
-    * Because we may have registered the printer profiles using a prior device
-    * ID-based UUID, remove both the old style UUID and current UUID for the
-    * printer.
-    */
-
-    CFUUIDRef deviceUUID;              /* Device UUID */
-
-    deviceUUID = ColorSyncCreateUUIDFromUInt32(_ppdHashName(p->name));
-    if (deviceUUID)
-    {
-      ColorSyncUnregisterDevice(kColorSyncPrinterDeviceClass, deviceUUID);
-      CFRelease(deviceUUID);
-    }
-  }
-}
-#endif /* __APPLE__ */
-
-
 /*
  * 'apply_printer_defaults()' - Apply printer default options to a job.
  */
@@ -5795,8 +5072,16 @@ static void
 create_job(cupsd_client_t  *con,       /* I - Client connection */
           ipp_attribute_t *uri)        /* I - Printer URI */
 {
+  int                  i;              /* Looping var */
   cupsd_printer_t      *printer;       /* Printer */
   cupsd_job_t          *job;           /* New job */
+  static const char * const forbidden_attrs[] =
+  {                                    /* List of forbidden attributes */
+    "compression",
+    "document-format",
+    "document-name",
+    "document-natural-language"
+  };
 
 
   cupsdLogMessage(CUPSD_LOG_DEBUG2, "create_job(%p[%d], %s)", con,
@@ -5817,6 +5102,29 @@ create_job(cupsd_client_t  *con, /* I - Client connection */
     return;
   }
 
+ /*
+  * Check for invalid Create-Job attributes and log a warning or error depending
+  * on whether cupsd is running in "strict conformance" mode...
+  */
+
+  for (i = 0;
+       i < (int)(sizeof(forbidden_attrs) / sizeof(forbidden_attrs[0]));
+       i ++)
+    if (ippFindAttribute(con->request, forbidden_attrs[i], IPP_TAG_ZERO))
+    {
+      if (StrictConformance)
+      {
+       send_ipp_status(con, IPP_BAD_REQUEST,
+                       _("The '%s' operation attribute cannot be supplied in a "
+                         "Create-Job request."), forbidden_attrs[i]);
+       return;
+      }
+
+      cupsdLogMessage(CUPSD_LOG_WARN,
+                      "Unexpected '%s' operation attribute in a Create-Job "
+                      "request.", forbidden_attrs[i]);
+    }
+
  /*
   * Create the job object...
   */
@@ -6539,13 +5847,11 @@ delete_printer(cupsd_client_t  *con,    /* I - Client connection */
   snprintf(filename, sizeof(filename), "%s/%s.data", CacheDir, printer->name);
   unlink(filename);
 
-#ifdef __APPLE__
  /*
   * Unregister color profiles...
   */
 
-  apple_unregister_profiles(printer);
-#endif /* __APPLE__ */
+  cupsdUnregisterColor(printer);
 
   if (dtype & CUPS_PRINTER_CLASS)
   {
index 6f834e3192a3f8c2a18ea72a6e31576d8a57d82f..9390e472e68e58a0f75722bf61951e265fc5f2fa 100644 (file)
@@ -287,16 +287,25 @@ cupsdCheckJobs(void)
   time_t               curtime;        /* Current time */
 
 
-  cupsdLogMessage(CUPSD_LOG_DEBUG2,
-                  "cupsdCheckJobs: %d active jobs, sleeping=%d, reload=%d",
-                  cupsArrayCount(ActiveJobs), Sleeping, NeedReload);
-
   curtime = time(NULL);
 
+  cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                  "cupsdCheckJobs: %d active jobs, sleeping=%d, reload=%d, "
+                  "curtime=%ld", cupsArrayCount(ActiveJobs), Sleeping,
+                  NeedReload, (long)curtime);
+
   for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs);
        job;
        job = (cupsd_job_t *)cupsArrayNext(ActiveJobs))
   {
+    cupsdLogMessage(CUPSD_LOG_DEBUG2,
+                    "cupsdCheckJobs: Job %d - dest=\"%s\", printer=%p, "
+                    "state=%d, cancel_time=%ld, hold_until=%ld, kill_time=%ld, "
+                    "pending_cost=%d, pending_timeout=%ld", job->id, job->dest,
+                    job->printer, job->state_value, (long)job->cancel_time,
+                    (long)job->hold_until, (long)job->kill_time,
+                    job->pending_cost, (long)job->pending_timeout);
+
    /*
     * Kill jobs if they are unresponsive...
     */
@@ -339,7 +348,6 @@ cupsdCheckJobs(void)
 
         cupsd_client_t *con;           /* Current client connection */
 
-
        for (con = (cupsd_client_t *)cupsArrayFirst(Clients);
             con;
             con = (cupsd_client_t *)cupsArrayNext(Clients))
@@ -431,7 +439,7 @@ cupsdCheckJobs(void)
           cupsdMarkDirty(CUPSD_DIRTY_JOBS);
        }
 
-        if (printer->state == IPP_PRINTER_IDLE)
+        if (!printer->job && printer->state == IPP_PRINTER_IDLE)
         {
         /*
          * Start the job...
@@ -3354,6 +3362,21 @@ finalize_job(cupsd_job_t *job,           /* I - Job */
 
   cupsArrayRemove(PrintingJobs, job);
 
+ /*
+  * Apply any PPD updates...
+  */
+
+  if (job->num_keywords)
+  {
+    if (cupsdUpdatePrinterPPD(job->printer, job->num_keywords, job->keywords))
+      cupsdSetPrinterAttrs(job->printer);
+
+    cupsFreeOptions(job->num_keywords, job->keywords);
+
+    job->num_keywords = 0;
+    job->keywords     = NULL;
+  }
+
  /*
   * Clear the printer <-> job association...
   */
@@ -4819,18 +4842,10 @@ update_job(cupsd_job_t *job)            /* I - Job to check */
       * Set attribute(s)...
       */
 
-      int              num_keywords;   /* Number of keywords */
-      cups_option_t    *keywords;      /* Keywords */
-
-
       cupsdLogJob(job, CUPSD_LOG_DEBUG, "PPD: %s", message);
 
-      num_keywords = cupsParseOptions(message, 0, &keywords);
-
-      if (cupsdUpdatePrinterPPD(job->printer, num_keywords, keywords))
-        cupsdSetPrinterAttrs(job->printer);
-
-      cupsFreeOptions(num_keywords, keywords);
+      job->num_keywords = cupsParseOptions(message, job->num_keywords,
+                                           &job->keywords);
     }
     else
     {
index e0b3a763ee031a4f0a59382965583aac57e009cb..e0250afee547cc95e0947a39b74a81bacafa578e 100644 (file)
@@ -80,6 +80,8 @@ struct cupsd_job_s                    /**** Job request ****/
   void                 *profile;       /* Security profile */
   cups_array_t         *history;       /* Debug log history */
   int                  progress;       /* Printing progress */
+  int                  num_keywords;   /* Number of PPD keywords */
+  cups_option_t                *keywords;      /* PPD keywords */
 };
 
 typedef struct cupsd_joblog_s          /**** Job log message ****/
index 0119342326fd680d123303d5a1b1993c5b7d8569..434c732ff7def7375477d474f2f5df3cf6d0d898 100644 (file)
@@ -4005,6 +4005,41 @@ load_ppd(cupsd_printer_t *p)             /* I - Printer */
         }
       }
 
+     /*
+      * media-size-supported
+      */
+
+      num_media = p->pc->num_sizes;
+      if (p->pc->custom_min_keyword)
+       num_media ++;
+
+      if ((attr = ippAddCollections(p->ppd_attrs, IPP_TAG_PRINTER,
+                                   "media-size-supported", num_media,
+                                   NULL)) != NULL)
+      {
+       val = attr->values;
+
+        for (i = p->pc->num_sizes, pwgsize = p->pc->sizes;
+            i > 0;
+            i --, pwgsize ++, val ++)
+       {
+         val->collection = ippNew();
+         ippAddInteger(val->collection, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                       "x-dimension", pwgsize->width);
+         ippAddInteger(val->collection, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+                       "y-dimension", pwgsize->length);
+        }
+
+        if (p->pc->custom_min_keyword)
+       {
+         val->collection = ippNew();
+         ippAddRange(val->collection, IPP_TAG_PRINTER, "x-dimension",
+                     p->pc->custom_min_width, p->pc->custom_max_width);
+         ippAddRange(val->collection, IPP_TAG_PRINTER, "y-dimension",
+                     p->pc->custom_min_length, p->pc->custom_max_length);
+        }
+      }
+
      /*
       * media-source-supported
       */
@@ -4797,7 +4832,8 @@ load_ppd(cupsd_printer_t *p)              /* I - Printer */
     else if (!strncmp(p->device_uri, "ipp://", 6) &&
             (strstr(p->device_uri, "/printers/") != NULL ||
              strstr(p->device_uri, "/classes/") != NULL ||
-             (strstr(p->device_uri, "._ipp.") != NULL &&
+             ((strstr(p->device_uri, "._ipp.") != NULL ||
+               strstr(p->device_uri, "._ipps.") != NULL) &&
               !strcmp(p->device_uri + strlen(p->device_uri) - 5,
                       "/cups"))))
     {
@@ -4918,6 +4954,8 @@ log_ipp_conformance(
     message = "Printer does not support REQUIRED Validate-Job operation.";
   else if (!strcmp(reason, "missing-get-printer-attributes"))
     message = "Printer does not support REQUIRED Get-Printer-Attributes operation.";
+  else if (!strcmp(reason, "missing-send-document"))
+    message = "Printer supports Create-Job but not Send-Document operation.";
   else if (!strcmp(reason, "missing-job-history"))
     message = "Printer does not provide REQUIRED job history.";
   else if (!strcmp(reason, "missing-job-id"))
index 833d2332b724010a8c39d0b55ef9d6edb355684c..2242ddd11514917dd579fea98c51a278d5ea28d8 100644 (file)
@@ -172,7 +172,8 @@ extern int          cupsdSetPrinterReasons(cupsd_printer_t *p,
                                               const char *s);
 extern void            cupsdSetPrinterState(cupsd_printer_t *p, ipp_pstate_t s,
                                             int update);
-#define                        cupsdStartPrinter(p,u) cupsdSetPrinterState((p), IPP_PRINTER_IDLE, (u))
+#define                        cupsdStartPrinter(p,u) cupsdSetPrinterState((p), \
+                                                  IPP_PRINTER_IDLE, (u))
 extern void            cupsdStopPrinter(cupsd_printer_t *p, int update);
 extern int             cupsdUpdatePrinterPPD(cupsd_printer_t *p,
                                              int num_keywords,
index 5e200eb71c391d535c6f7598db7d75c6945fa88f..a5a31c59bd54831834a26718adfded6b9abc97c1 100644 (file)
@@ -3,7 +3,7 @@
  *
  *   Server start/stop routines for the CUPS scheduler.
  *
- *   Copyright 2007-2011 by Apple Inc.
+ *   Copyright 2007-2012 by Apple Inc.
  *   Copyright 1997-2006 by Easy Software Products, all rights reserved.
  *
  *   These coded instructions, statements, and computer programs are the
@@ -44,6 +44,12 @@ static int           started = 0;    /* Did we start the server already? */
 void
 cupsdStartServer(void)
 {
+ /*
+  * Start color management (as needed)...
+  */
+
+  cupsdStartColor();
+
  /*
   * Create the default security profile...
   */
@@ -94,7 +100,13 @@ cupsdStopServer(void)
     return;
 
  /*
-  * Close all network clients and stop all jobs...
+  * Stop color management (as needed)...
+  */
+
+  cupsdStopColor();
+
+ /*
+  * Close all network clients...
   */
 
   cupsdCloseAllClients();
index 6638db5ead66b06def1ea762f077c4ec24aa3e0d..945149f729fd40c58aa02f96b7678c56634f72c2 100644 (file)
@@ -974,11 +974,13 @@ sysUpdate(void)
             p = (cupsd_printer_t *)cupsArrayNext(Printers))
          cupsdDeregisterPrinter(p, 1);
 
+#  if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
        /*
         * Update the computer name and BTMM domain list...
        */
 
        cupsdUpdateDNSSDName();
+#  endif /* HAVE_DNSSD || HAVE_AVAHI */
 
        /*
        * Now re-register them...
index 6d53d63a51146a41112a9e5dae387b1e536b0768..1f138c7a1c649775f2a594f96edbc8bfbb1f2e70 100644 (file)
@@ -173,7 +173,9 @@ copy_cdsa_certificate(
                                        /* Server name */
   CFMutableDictionaryRef query = NULL; /* Query qualifiers */
   CFArrayRef           list = NULL;    /* Keychain list */
+#    if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
   char                 localname[1024];/* Local hostname */
+#    endif /* HAVE_DNSSD || HAVE_AVAHI */
 #  elif defined(HAVE_SECIDENTITYSEARCHCREATEWITHPOLICY)
   SecPolicyRef         policy = NULL;  /* Policy ref */
   SecPolicySearchRef   policy_search = NULL;
@@ -232,6 +234,7 @@ copy_cdsa_certificate(
 
   err = SecItemCopyMatching(query, (CFTypeRef *)&identity);
 
+#    if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
   if (err && DNSSDHostName)
   {
    /*
@@ -265,6 +268,7 @@ copy_cdsa_certificate(
 
     err = SecItemCopyMatching(query, (CFTypeRef *)&identity);
   }
+#    endif /* HAVE_DNSSD || HAVE_AVAHI */
 
   if (err)
   {
@@ -320,6 +324,7 @@ copy_cdsa_certificate(
 
   err = SecIdentitySearchCopyNext(search, &identity);
 
+#    if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
   if (err && DNSSDHostName)
   {
    /*
@@ -357,6 +362,7 @@ copy_cdsa_certificate(
     err = SecIdentitySearchCopyNext(search, &identity);
 
   }
+#    endif /* HAVE_DNSSD || HAVE_AVAHI */
 
   if (err)
   {
@@ -439,18 +445,22 @@ make_certificate(cupsd_client_t *con)     /* I - Client connection */
                *envp[MAX_ENV + 1],     /* Environment variables */
                keychain[1024],         /* Keychain argument */
                infofile[1024],         /* Type-in information for cert */
+#  if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
                localname[1024],        /* Local hostname */
+#  endif /* HAVE_DNSSD || HAVE_AVAHI */
                *servername;            /* Name of server in cert */
   cups_file_t  *fp;                    /* Seed/info file */
   int          infofd;                 /* Info file descriptor */
 
 
+#  if defined(HAVE_DNSSD) || defined(HAVE_AVAHI)
   if (con->servername && isdigit(con->servername[0] & 255) && DNSSDHostName)
   {
     snprintf(localname, sizeof(localname), "%s.local", DNSSDHostName);
     servername = localname;
   }
   else
+#  endif /* HAVE_DNSSD || HAVE_AVAHI */
     servername = con->servername;
 
  /*
index d100a3056920ff8bbb97a2d86bbdabf74514152b..03a25ec1614b1e09e05231dacf596a204411d6a7 100644 (file)
@@ -46,7 +46,7 @@ main(int  argc,                               /* I - Number of command-line arguments */
   int          i, j;                   /* Looping vars */
   int          job_id;                 /* Job ID */
   char         *printer,               /* Printer name */
-               *instance,              /* Instance name */ 
+               *instance,              /* Instance name */
                *val,                   /* Option value */
                *title;                 /* Job title */
   int          priority;               /* Job priority (1-100) */
@@ -121,7 +121,7 @@ main(int  argc,                             /* I - Number of command-line arguments */
               cupsSetUser(argv[i]);
            }
            break;
-           
+
         case 'c' : /* Copy to spool dir (always enabled) */
            break;
 
@@ -629,8 +629,9 @@ main(int  argc,                             /* I - Number of command-line arguments */
 
     if (cupsFinishDocument(CUPS_HTTP_DEFAULT, printer) != IPP_OK)
     {
+      _cupsLangPrintf(stderr, "%s: %s", argv[0], cupsLastErrorString());
       cupsCancelJob2(CUPS_HTTP_DEFAULT, printer, job_id, 0);
-      job_id = 0;
+      return (1);
     }
   }
 
index 142fbb243fe762157c177e7bc80d7e856913d4e1..541e786a6af0e159abcf74839da14a6942a6ffbd 100644 (file)
@@ -6,7 +6,7 @@
 <TBODY>
 {[job_id]
 <TR VALIGN="TOP">
-<TD><A HREF="{job_printer_uri}">{job_printer_name}</A>-{job_id}{?phone? ({phone})}&nbsp;</TD>
+<TD><A HREF="{job_printer_uri}">{job_printer_name}</A>-{job_id}{?phone? ({phone}):}&nbsp;</TD>
 <TD>{?job_name=?Unknown:{job_name}}&nbsp;</TD>
 <TD>{?job_originating_user_name=?Withheld:{job_originating_user_name}}&nbsp;</TD>
 <TD>{job_k_octets}k&nbsp;</TD>
index 6dfd6f50e85031803a1cd966e6f4cd42807f0e9e..e4a8ed4ac7db6f919128791774cf4b0582ebcd32 100644 (file)
@@ -4,7 +4,7 @@
 #
 #   Test the lpadmin command.
 #
-#   Copyright 2007-2009 by Apple Inc.
+#   Copyright 2007-2012 by Apple Inc.
 #   Copyright 1997-2005 by Easy Software Products, all rights reserved.
 #
 #   These coded instructions, statements, and computer programs are the
@@ -50,6 +50,18 @@ else
 fi
 echo ""
 
+echo "Add Shared Printer Test"
+echo ""
+echo "    lpadmin -p Test3 -E -v ipp://localhost:8631/printers/Test2 -m raw"
+$VALGRIND ../systemv/lpadmin -p Test3 -E -v ipp://localhost:8631/printers/Test2 -m raw 2>&1
+if test $? != 0; then
+       echo "    FAILED"
+       exit 1
+else
+       echo "    PASSED"
+fi
+echo ""
+
 #
 # End of "$Id: 5.1-lpadmin.sh 7494 2008-04-25 18:36:46Z mike $".
 #
index f74e79ba91dce8b9a19ae9210e1929bda6d23c42..aa326a8fcb104334c633718a7ce8d642a590a446 100644 (file)
@@ -4,7 +4,7 @@
 #
 #   Test the lp command.
 #
-#   Copyright 2007-2011 by Apple Inc.
+#   Copyright 2007-2012 by Apple Inc.
 #   Copyright 1997-2005 by Easy Software Products, all rights reserved.
 #
 #   These coded instructions, statements, and computer programs are the
@@ -28,8 +28,8 @@ echo ""
 
 echo "LP Destination Test"
 echo ""
-echo "    lp -d Test2 testfile.jpg"
-$VALGRIND ../systemv/lp -d Test2 testfile.jpg 2>&1
+echo "    lp -d Test3 -o fit-to-page testfile.jpg"
+$VALGRIND ../systemv/lp -d Test3 -o fit-to-page testfile.jpg 2>&1
 if test $? != 0; then
        echo "    FAILED"
        exit 1
index 17646aa88431b116304ad167e967a7932197a045..9a26e75cb7c72697ac8d6c2afb0f8757260fc8e2 100644 (file)
@@ -4,7 +4,7 @@
 #
 #   Test the lpr command.
 #
-#   Copyright 2007-2011 by Apple Inc.
+#   Copyright 2007-2012 by Apple Inc.
 #   Copyright 1997-2005 by Easy Software Products, all rights reserved.
 #
 #   These coded instructions, statements, and computer programs are the
@@ -28,8 +28,8 @@ echo ""
 
 echo "LPR Destination Test"
 echo ""
-echo "    lpr -P Test2 testfile.jpg"
-$VALGRIND ../berkeley/lpr -P Test2 testfile.jpg 2>&1
+echo "    lpr -P Test3 -o fit-to-page testfile.jpg"
+$VALGRIND ../berkeley/lpr -P Test3 -o fit-to-page testfile.jpg 2>&1
 if test $? != 0; then
        echo "    FAILED"
        exit 1
index cd6f5f2d5436395a4bad30907c29901fe47e9f32..ad85720ccb3361a0dc2adc5a7c4e8eddcb950380 100644 (file)
@@ -32,6 +32,7 @@ DATAFILES     =       \
                        onepage-letter.pdf \
                        onepage-letter.ps \
                        testfile.jpg \
+                       testfile.pcl \
                        testfile.pdf \
                        testfile.ps \
                        testfile.txt
index 23f2a0bdef6a9ddc0838d7acb650011c9b9b8bef..5d67ff678f5571348004d9b7da0dd941388f2954 100644 (file)
@@ -156,7 +156,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
        STATUS successful-ok
        STATUS client-error-document-format-not-supported
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -671,7 +671,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
        ATTR name requesting-user-name $user
 
        STATUS successful-ok
-       EXPECT job-state OF-TYPE unknown|enum IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >6 REPEAT-NO-MATCH
+       EXPECT job-state OF-TYPE unknown|enum IN-GROUP job-attributes-tag COUNT 1 WITH-VALUE >6 REPEAT-NO-MATCH REPEAT-LIMIT 30
        DISPLAY job-state
 }
 
@@ -833,7 +833,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
        STATUS successful-ok
        STATUS client-error-document-format-not-supported
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -945,7 +945,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1262,7 +1262,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
        STATUS successful-ok
        STATUS client-error-document-format-not-supported
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1300,7 +1300,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1338,7 +1338,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1374,7 +1374,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1412,7 +1412,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1450,7 +1450,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1488,7 +1488,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1524,7 +1524,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1562,7 +1562,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1600,7 +1600,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1636,7 +1636,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1672,7 +1672,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1708,7 +1708,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1744,7 +1744,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1780,7 +1780,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1820,7 +1820,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1858,7 +1858,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1896,7 +1896,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1934,7 +1934,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -1974,7 +1974,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -2012,7 +2012,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -2050,7 +2050,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -2088,7 +2088,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -2128,7 +2128,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -2166,7 +2166,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -2204,7 +2204,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -2242,7 +2242,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -2280,7 +2280,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
@@ -2315,7 +2315,7 @@ DEFINE IPP_URI_SCHEME "/^ipps?://.+$$/"
 
        STATUS successful-ok
        STATUS server-error-job-canceled
-       STATUS server-error-busy REPEAT-MATCH
+       STATUS server-error-busy REPEAT-MATCH REPEAT-LIMIT 10
 
        EXPECT job-uri OF-TYPE uri COUNT 1 IN-GROUP job-attributes-tag WITH-VALUE "$IPP_URI_SCHEME"
        EXPECT job-id OF-TYPE integer COUNT 1 IN-GROUP job-attributes-tag
index 1663da770fb3def1f6db44f60ca0ce923f5bcedb..696a8922faedf94a4cdf2539f051afdc9c3a9990 100644 (file)
@@ -101,7 +101,8 @@ typedef struct _cups_expect_s               /**** Expected attribute info ****/
                *define_match,          /* Variable to define on match */
                *define_no_match,       /* Variable to define on no-match */
                *define_value;          /* Variable to define with value */
-  int          repeat_match,           /* Repeat test on match */
+  int          repeat_limit,           /* Maximum number of times to repeat */
+               repeat_match,           /* Repeat test on match */
                repeat_no_match,        /* Repeat test on no match */
                with_flags,             /* WITH flags  */
                count;                  /* Expected count if > 0 */
@@ -113,7 +114,8 @@ typedef struct _cups_status_s               /**** Status info ****/
   ipp_status_t status;                 /* Expected status code */
   char         *if_defined,            /* Only if variable is defined */
                *if_not_defined;        /* Only if variable is not defined */
-  int          repeat_match,           /* Repeat the test when it does not match */
+  int          repeat_limit,           /* Maximum number of times to repeat */
+               repeat_match,           /* Repeat the test when it does not match */
                repeat_no_match;        /* Repeat the test when it matches */
 } _cups_status_t;
 
@@ -456,6 +458,9 @@ main(int  argc,                             /* I - Number of command-line args */
                   set_variable(&vars, "filetype", "text/html");
                 else if (!_cups_strcasecmp(ext, ".jpg"))
                   set_variable(&vars, "filetype", "image/jpeg");
+                else if (!_cups_strcasecmp(ext, ".pcl") ||
+                         !_cups_strcasecmp(ext, ".pcl.gz"))
+                  set_variable(&vars, "filetype", "application/vnd.hp-PCL");
                 else if (!_cups_strcasecmp(ext, ".pdf"))
                   set_variable(&vars, "filetype", "application/pdf");
                 else if (!_cups_strcasecmp(ext, ".png"))
@@ -750,6 +755,9 @@ do_tests(_cups_vars_t *vars,                /* I - Variables */
                show_header = 1,        /* Show the test header? */
                ignore_errors,          /* Ignore test failures? */
                skip_previous = 0,      /* Skip on previous test failure? */
+               repeat_count,           /* Repeat count */
+               repeat_interval,        /* Repeat interval */
+               repeat_prev,            /* Previous repeat interval */
                repeat_test;            /* Repeat a test? */
   http_t       *http = NULL;           /* HTTP connection to server */
   FILE         *fp = NULL;             /* Test file */
@@ -1168,6 +1176,7 @@ do_tests(_cups_vars_t *vars,              /* I - Variables */
           _cups_strcasecmp(token, "IF-NOT-DEFINED") &&
           _cups_strcasecmp(token, "IN-GROUP") &&
           _cups_strcasecmp(token, "OF-TYPE") &&
+          _cups_strcasecmp(token, "REPEAT-LIMIT") &&
           _cups_strcasecmp(token, "REPEAT-MATCH") &&
           _cups_strcasecmp(token, "REPEAT-NO-MATCH") &&
           _cups_strcasecmp(token, "SAME-COUNT-AS") &&
@@ -1177,6 +1186,7 @@ do_tests(_cups_vars_t *vars,              /* I - Variables */
 
       if (_cups_strcasecmp(token, "IF-DEFINED") &&
           _cups_strcasecmp(token, "IF-NOT-DEFINED") &&
+          _cups_strcasecmp(token, "REPEAT-LIMIT") &&
           _cups_strcasecmp(token, "REPEAT-MATCH") &&
           _cups_strcasecmp(token, "REPEAT-NO-MATCH"))
         last_status = NULL;
@@ -1796,6 +1806,7 @@ do_tests(_cups_vars_t *vars,              /* I - Variables */
 
        last_status->if_defined      = NULL;
        last_status->if_not_defined  = NULL;
+       last_status->repeat_limit    = 1000;
        last_status->repeat_match    = 0;
        last_status->repeat_no_match = 0;
       }
@@ -1823,6 +1834,7 @@ do_tests(_cups_vars_t *vars,              /* I - Variables */
        num_expects ++;
 
        memset(last_expect, 0, sizeof(_cups_expect_t));
+       last_expect->repeat_limit = 1000;
 
         if (token[0] == '!')
         {
@@ -1968,6 +1980,33 @@ do_tests(_cups_vars_t *vars,             /* I - Variables */
          goto test_exit;
        }
       }
+      else if (!_cups_strcasecmp(token, "REPEAT-LIMIT"))
+      {
+       if (!get_token(fp, token, sizeof(token), &linenum))
+       {
+         print_fatal_error("Missing REPEAT-LIMIT value on line %d.", linenum);
+         pass = 0;
+         goto test_exit;
+       }
+       else if (atoi(token) <= 0)
+       {
+         print_fatal_error("Bad REPEAT-LIMIT value on line %d.", linenum);
+         pass = 0;
+         goto test_exit;
+       }
+
+        if (last_status)
+          last_status->repeat_limit = atoi(token);
+       else if (last_expect)
+         last_expect->repeat_limit = atoi(token);
+       else
+       {
+         print_fatal_error("REPEAT-LIMIT without a preceding EXPECT or STATUS "
+                           "on line %d.", linenum);
+         pass = 0;
+         goto test_exit;
+       }
+      }
       else if (!_cups_strcasecmp(token, "REPEAT-MATCH"))
       {
         if (last_status)
@@ -2210,8 +2249,14 @@ do_tests(_cups_vars_t *vars,             /* I - Variables */
       goto skip_error;
     }
 
+    repeat_count    = 0;
+    repeat_interval = 1;
+    repeat_prev     = 1;
+
     do
     {
+      repeat_count ++;
+
       status = HTTP_OK;
 
       if (transfer == _CUPS_TRANSFER_CHUNKED ||
@@ -2292,7 +2337,7 @@ do_tests(_cups_vars_t *vars,              /* I - Variables */
            status   = httpGetStatus(http);
          }
 
-         if (!Cancel && status == HTTP_ERROR &&
+         if (!Cancel && status == HTTP_ERROR && http->error != EINVAL &&
 #ifdef WIN32
              http->error != WSAETIMEDOUT)
 #else
@@ -2315,7 +2360,7 @@ do_tests(_cups_vars_t *vars,              /* I - Variables */
        }
       }
 
-      if (!Cancel && status == HTTP_ERROR &&
+      if (!Cancel && status == HTTP_ERROR && http->error != EINVAL &&
 #ifdef WIN32
          http->error != WSAETIMEDOUT)
 #else
@@ -2592,12 +2637,14 @@ do_tests(_cups_vars_t *vars,            /* I - Variables */
 
          if (response->request.status.status_code == statuses[i].status)
          {
-           if (statuses[i].repeat_match)
+           if (statuses[i].repeat_match &&
+               repeat_count < statuses[i].repeat_limit)
              repeat_test = 1;
 
            break;
          }
-         else if (statuses[i].repeat_no_match)
+         else if (statuses[i].repeat_no_match &&
+                  repeat_count < statuses[i].repeat_limit)
            repeat_test = 1;
        }
 
@@ -2663,7 +2710,8 @@ do_tests(_cups_vars_t *vars,              /* I - Variables */
               }
             }
 
-           if (expect->repeat_no_match)
+           if (expect->repeat_no_match &&
+               repeat_count < expect->repeat_limit)
              repeat_test = 1;
 
            continue;
@@ -2697,7 +2745,8 @@ do_tests(_cups_vars_t *vars,              /* I - Variables */
                         buffer, sizeof(buffer));
            }
 
-           if (expect->repeat_no_match)
+           if (expect->repeat_no_match &&
+               repeat_count < expect->repeat_limit)
              repeat_test = 1;
 
            continue;
@@ -2714,7 +2763,8 @@ do_tests(_cups_vars_t *vars,              /* I - Variables */
                          expect->count, found->num_values);
            }
 
-           if (expect->repeat_no_match)
+           if (expect->repeat_no_match &&
+               repeat_count < expect->repeat_limit)
              repeat_test = 1;
 
            continue;
@@ -2743,7 +2793,8 @@ do_tests(_cups_vars_t *vars,              /* I - Variables */
                              expect->same_count_as, attrptr->num_values);
              }
 
-             if (expect->repeat_no_match)
+             if (expect->repeat_no_match &&
+                 repeat_count < expect->repeat_limit)
                repeat_test = 1;
 
              continue;
@@ -2756,7 +2807,8 @@ do_tests(_cups_vars_t *vars,              /* I - Variables */
          if (found && expect->define_value)
            set_variable(vars, expect->define_value, buffer);
 
-         if (found && expect->repeat_match)
+         if (found && expect->repeat_match &&
+             repeat_count < expect->repeat_limit)
            repeat_test = 1;
        }
       }
@@ -2767,7 +2819,22 @@ do_tests(_cups_vars_t *vars,             /* I - Variables */
       */
 
       if (repeat_test)
-        sleep(1);
+      {
+       if (Output == _CUPS_OUTPUT_TEST)
+        {
+          printf("%04d]\n", repeat_count);
+          fflush(stdout);
+        }
+
+        sleep(repeat_interval);
+        repeat_interval = _cupsNextDelay(repeat_interval, &repeat_prev);
+
+       if (Output == _CUPS_OUTPUT_TEST)
+       {
+         printf("    %-68.68s [", name);
+         fflush(stdout);
+       }
+      }
     }
     while (repeat_test);
 
index 03e80310206b2814d894070801b6f1e25f532a3f..ff589e9e0666318609515086e4327f03aff9ee08 100755 (executable)
@@ -5,7 +5,7 @@
 #   Perform the complete set of IPP compliance tests specified in the
 #   CUPS Software Test Plan.
 #
-#   Copyright 2007-2011 by Apple Inc.
+#   Copyright 2007-2012 by Apple Inc.
 #   Copyright 1997-2007 by Easy Software Products, all rights reserved.
 #
 #   These coded instructions, statements, and computer programs are the
 
 argcount=$#
 
+#
+# Don't allow "make check" or "make test" to be run by root...
+#
+
+if test "x`id -u`" = x0; then
+       echo Please run this as a normal user. Not supported when run as root.
+       exit 1
+fi
+
+#
+# Force the permissions of the files we create...
+#
+
+umask 022
+
 #
 # Make the IPP test program...
 #
@@ -368,10 +383,11 @@ else
 fi
 
 cat >/tmp/cups-$user/cupsd.conf <<EOF
+StrictConformance Yes
 Browsing Off
 FileDevice yes
 Printcap
-Listen 127.0.0.1:$port
+Listen localhost:$port
 User $user
 ServerRoot /tmp/cups-$user
 StateDir /tmp/cups-$user
@@ -395,9 +411,7 @@ LogTimeFormat usecs
 PreserveJobHistory Yes
 <Policy default>
 <Limit All>
-Order Deny,Allow
-Deny from all
-Allow from 127.0.0.1
+Order Allow,Deny
 $encryption
 </Limit>
 </Policy>
@@ -605,11 +619,18 @@ echo `date "+%Y-%m-%d"` by $user on `hostname`. >>$strfile
 echo "<PRE>" >>$strfile
 
 fail=0
-for file in 4*.test; do
+for file in 4*.test ipp-2.1.test; do
        echo $ac_n "Performing $file: $ac_c"
        echo "" >>$strfile
 
-       $VALGRIND ./ipptool -tI ipp://localhost:$port/printers $file >> $strfile
+       if test $file = ipp-2.1.test; then
+               uri="ipp://localhost:$port/printers/Test1"
+               options="-V 2.1 -d NOPRINT=1 -f testfile.ps"
+       else
+               uri="ipp://localhost:$port/printers"
+               options=""
+       fi
+       $VALGRIND ./ipptool -tI $options $uri $file >> $strfile
        status=$?
 
        if test $status != 0; then
@@ -710,9 +731,21 @@ else
        echo "<P>PASS: Printer 'Test2' correctly produced $count page(s).</P>" >>$strfile
 fi
 
+# Paged printed on Test3
+count=`$GREP '^Test3 ' /tmp/cups-$user/log/page_log | grep -v total | awk 'BEGIN{count=0}{count=count+$7}END{print count}'`
+expected=2
+if test $count != $expected; then
+       echo "FAIL: Printer 'Test3' produced $count page(s), expected $expected."
+       echo "<P>FAIL: Printer 'Test3' produced $count page(s), expected $expected.</P>" >>$strfile
+       fail=`expr $fail + 1`
+else
+       echo "PASS: Printer 'Test3' correctly produced $count page(s)."
+       echo "<P>PASS: Printer 'Test3' correctly produced $count page(s).</P>" >>$strfile
+fi
+
 # Requests logged
 count=`wc -l /tmp/cups-$user/log/access_log | awk '{print $1}'`
-expected=`expr 37 + 18 + $pjobs \* 8 + $pprinters \* $pjobs \* 4`
+expected=`expr 37 + 18 + 28 + $pjobs \* 8 + $pprinters \* $pjobs \* 4`
 if test $count != $expected; then
        echo "FAIL: $count requests logged, expected $expected."
        echo "<P>FAIL: $count requests logged, expected $expected.</P>" >>$strfile
@@ -782,10 +815,10 @@ fi
 
 # Error log messages
 count=`$GREP '^E ' /tmp/cups-$user/log/error_log | wc -l | awk '{print $1}'`
-if test $count != 18; then
-       echo "FAIL: $count error messages, expected 18."
+if test $count != 33; then
+       echo "FAIL: $count error messages, expected 33."
        $GREP '^E ' /tmp/cups-$user/log/error_log
-       echo "<P>FAIL: $count error messages, expected 18.</P>" >>$strfile
+       echo "<P>FAIL: $count error messages, expected 33.</P>" >>$strfile
        echo "<PRE>" >>$strfile
        $GREP '^E ' /tmp/cups-$user/log/error_log | sed -e '1,$s/&/&amp;/g' -e '1,$s/</&lt;/g' >>$strfile
        echo "</PRE>" >>$strfile
diff --git a/test/testfile.pcl b/test/testfile.pcl
new file mode 100644 (file)
index 0000000..4b86597
--- /dev/null
@@ -0,0 +1,60 @@
+\eEAll work and no play makes Johhny a dull boy.  All work and no\r
+play makes Johhny a dull boy.  All work and no play makes Johhny\r
+a dull boy.  All work and no play makes Johhny a dull boy.  All\r
+work and no play makes Johhny a dull boy.  All work and no play\r
+makes Johhny a dull boy.  All work and no play makes Johhny a\r
+dull boy.  All work and no play makes Johhny a dull boy.  All\r
+work and no play makes Johhny a dull boy.  All work and no play\r
+makes Johhny a dull boy.  All work and no play makes Johhny a\r
+dull boy. All work and no play makes Johhny a dull boy.  All\r
+work and no play makes Johhny a dull boy.  All work and no play\r
+makes Johhny a dull boy.  All work and no play makes Johhny a\r
+dull boy.  All work and no play makes Johhny a dull boy.  All\r
+work and no play makes Johhny a dull boy.  All work and no play\r
+makes Johhny a dull boy.  All work and no play makes Johhny a\r
+dull boy.  All work and no play makes Johhny a dull boy.  All\r
+work and no play makes Johhny a dull boy.  All work and no play\r
+makes Johhny a dull boy. All work and no play makes Johhny a\r
+dull boy.  All work and no play makes Johhny a dull boy.  All\r
+work and no play makes Johhny a dull boy.  All work and no play\r
+makes Johhny a dull boy.  All work and no play makes Johhny a\r
+dull boy.  All work and no play makes Johhny a dull boy.  All\r
+work and no play makes Johhny a dull boy.  All work and no play\r
+makes Johhny a dull boy.  All work and no play makes Johhny a\r
+dull boy.  All work and no play makes Johhny a dull boy.  All\r
+work and no play makes Johhny a dull boy. All work and no play\r
+makes Johhny a dull boy.  All work and no play makes Johhny a\r
+dull boy.  All work and no play makes Johhny a dull boy.  All\r
+work and no play makes Johhny a dull boy.  All work and no play\r
+makes Johhny a dull boy.  All work and no play makes Johhny a\r
+dull boy.  All work and no play makes Johhny a dull boy.  All\r
+work and no play makes Johhny a dull boy.  All work and no play\r
+makes Johhny a dull boy.  All work and no play makes Johhny a\r
+dull boy.  All work and no play makes Johhny a dull boy. All\r
+work and no play makes Johhny a dull boy.  All work and no play\r
+makes Johhny a dull boy.  All work and no play makes Johhny a\r
+dull boy.  All work and no play makes Johhny a dull boy.  All\r
+work and no play makes Johhny a dull boy.  All work and no play\r
+makes Johhny a dull boy.  All work and no play makes Johhny a\r
+dull boy.  All work and no play makes Johhny a dull boy.  All\r
+work and no play makes Johhny a dull boy.  All work and no play\r
+makes Johhny a dull boy.  All work and no play makes Johhny a\r
+dull boy. All work and no play makes Johhny a dull boy.  All\r
+work and no play makes Johhny a dull boy.  All work and no play\r
+makes Johhny a dull boy.  All work and no play makes Johhny a\r
+dull boy.  All work and no play makes Johhny a dull boy.  All\r
+work and no play makes Johhny a dull boy.  All work and no play\r
+makes Johhny a dull boy.  All work and no play makes Johhny a\r
+dull boy.  All work and no play makes Johhny a dull boy.  All\r
+work and no play makes Johhny a dull boy.  All work and no play\r
+makes Johhny a dull boy. All work and no play makes Johhny a\r
+dull boy.  All work and no play makes Johhny a dull boy.  All\r
+work and no play makes Johhny a dull boy.  All work and no play\r
+makes Johhny a dull boy.  All work and no play makes Johhny a\r
+dull boy.  All work and no play makes Johhny a dull boy.  All\r
+work and no play makes Johhny a dull boy.  All work and no play\r
+makes Johhny a dull boy.  All work and no play makes Johhny a\r
+dull boy.  All work and no play makes Johhny a dull boy.  All\r
+work and no play makes Johhny a dull boy. All work and no play\r
+makes Johhny a dull boy.  All work and no play makes Johhny a\r
+dull boy.  All work and no play makes Johhny a dull boy.\f\eE\r
diff --git a/tools/testbtmm.c b/tools/testbtmm.c
new file mode 100644 (file)
index 0000000..bd6379f
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Simple test program that lists the Back to My Mac domains on a Mac.
+ *
+ * Compile with:
+ *
+ *   clang -o testbtmm -g testbtmm.c -framework SystemConfiguration -framework CoreFoundation
+ */
+
+#include <stdio.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+
+
+/*
+ * 'dnssdAddAlias()' - Add a DNS-SD alias name.
+ */
+
+static void
+show_domain(const void *key,           /* I - Key */
+           const void *value,          /* I - Value (domain) */
+           void       *context)        /* I - Unused */
+{
+  char valueStr[1024];                 /* Domain string */
+
+
+  (void)key;
+  (void)context;
+
+  if (CFGetTypeID((CFStringRef)value) == CFStringGetTypeID() &&
+      CFStringGetCString((CFStringRef)value, valueStr, sizeof(valueStr),
+                         kCFStringEncodingUTF8))
+    printf("Back to My Mac domain: \"%s\"\n", valueStr);
+  else
+    puts("Bad Back to My Mac domain in dynamic store.");
+}
+
+
+int
+main(void)
+{
+  SCDynamicStoreRef sc;                        /* Context for dynamic store */
+  CFDictionaryRef btmm;                        /* Back-to-My-Mac domains */
+
+
+  sc = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("cups"), NULL, NULL);
+
+  if (!sc)
+  {
+    puts("Unable to open dynamic store.");
+    exit(1);
+  }
+
+  btmm = SCDynamicStoreCopyValue(sc, CFSTR("Setup:/Network/BackToMyMac"));
+  if (btmm && CFGetTypeID(btmm) == CFDictionaryGetTypeID())
+  {
+    printf("%d Back to My Mac domains.\n", (int)CFDictionaryGetCount(btmm));
+    CFDictionaryApplyFunction(btmm, show_domain, NULL);
+  }
+  else if (btmm)
+    puts("Bad Back to My Mac data in dynamic store.");
+  else
+    puts("No Back to My Mac domains.");
+
+  return (1);
+}
index 429561178cdd59e7aa4c123ea8641b963540fffc..4bc8343ba29c5916d3af48fb656069fb844d9984 100644 (file)
                728FB7EC1536161C005426E1 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = ../../../../../usr/lib/libz.dylib; sourceTree = "<group>"; };
                728FB7EF1536167A005426E1 /* libiconv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libiconv.dylib; path = ../../../../../usr/lib/libiconv.dylib; sourceTree = "<group>"; };
                728FB7F01536167A005426E1 /* libresolv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libresolv.dylib; path = ../../../../../usr/lib/libresolv.dylib; sourceTree = "<group>"; };
+               72A4332F155844CF002E172D /* libcups_static.a */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libcups_static.a; sourceTree = BUILT_PRODUCTS_DIR; };
                72C16CB8137B195D007E4BF4 /* file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = file.c; path = ../scheduler/file.c; sourceTree = SOURCE_ROOT; };
-               72F75A4C1336F31B004BB496 /* libcups_static.a */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; name = libcups_static.a; path = "/Users/msweet/c/cups-trunk/xcode/build/Release/libcups_static.a"; sourceTree = "<absolute>"; };
                72F75A521336F950004BB496 /* cupstestppd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cupstestppd; sourceTree = BUILT_PRODUCTS_DIR; };
                72F75A5B1336F988004BB496 /* cupstestppd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cupstestppd.c; path = ../systemv/cupstestppd.c; sourceTree = "<group>"; };
                72F75A611336F9A3004BB496 /* libcupsimage.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libcupsimage.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
                                270CCDA7135E3C9E00007BE2 /* testmime */,
                                726AD6F7135E88F0002C930D /* ippserver */,
                                278C58CB136B640300836530 /* testhttp */,
+                               72A4332F155844CF002E172D /* libcups_static.a */,
                        );
                        name = Products;
                        sourceTree = "<group>";
                        );
                        name = libcups_static;
                        productName = libcups;
-                       productReference = 72F75A4C1336F31B004BB496 /* libcups_static.a */;
+                       productReference = 72A4332F155844CF002E172D /* libcups_static.a */;
                        productType = "com.apple.product-type.library.dynamic";
                };
                2766835B1337A9B6000D33D0 /* cupsctl */ = {
                72BF96371333042100B1EAD7 /* Project object */ = {
                        isa = PBXProject;
                        attributes = {
-                               LastUpgradeCheck = 0420;
+                               LastUpgradeCheck = 0440;
                                ORGANIZATIONNAME = "Apple Inc.";
                        };
                        buildConfigurationList = 72BF963A1333042100B1EAD7 /* Build configuration list for PBXProject "CUPS" */;